1/* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996-1999 by Internet Software Consortium 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* ev_waits.c - implement deferred function calls for the eventlib 19 * vix 05dec95 [initial] 20 */ 21 22#if !defined(LINT) && !defined(CODECENTER) 23static const char rcsid[] = "$Id: ev_waits.c,v 1.4 2005/04/27 04:56:36 sra Exp $"; 24#endif 25 26#include "port_before.h" 27#include "fd_setsize.h" 28 29#include <errno.h> 30 31#include <isc/eventlib.h> 32#include <isc/assertions.h> 33#include "eventlib_p.h" 34 35#include "port_after.h" 36 37/* Forward. */ 38 39static void print_waits(evContext_p *ctx); 40static evWaitList * evNewWaitList(evContext_p *); 41static void evFreeWaitList(evContext_p *, evWaitList *); 42static evWaitList * evGetWaitList(evContext_p *, const void *, int); 43 44 45/* Public. */ 46 47/*% 48 * Enter a new wait function on the queue. 49 */ 50int 51evWaitFor(evContext opaqueCtx, const void *tag, 52 evWaitFunc func, void *uap, evWaitID *id) 53{ 54 evContext_p *ctx = opaqueCtx.opaque; 55 evWait *new; 56 evWaitList *wl = evGetWaitList(ctx, tag, 1); 57 58 OKNEW(new); 59 new->func = func; 60 new->uap = uap; 61 new->tag = tag; 62 new->next = NULL; 63 if (wl->last != NULL) 64 wl->last->next = new; 65 else 66 wl->first = new; 67 wl->last = new; 68 if (id != NULL) 69 id->opaque = new; 70 if (ctx->debug >= 9) 71 print_waits(ctx); 72 return (0); 73} 74 75/*% 76 * Mark runnable all waiting functions having a certain tag. 77 */ 78int 79evDo(evContext opaqueCtx, const void *tag) { 80 evContext_p *ctx = opaqueCtx.opaque; 81 evWaitList *wl = evGetWaitList(ctx, tag, 0); 82 evWait *first; 83 84 if (!wl) { 85 errno = ENOENT; 86 return (-1); 87 } 88 89 first = wl->first; 90 INSIST(first != NULL); 91 92 if (ctx->waitDone.last != NULL) 93 ctx->waitDone.last->next = first; 94 else 95 ctx->waitDone.first = first; 96 ctx->waitDone.last = wl->last; 97 evFreeWaitList(ctx, wl); 98 99 return (0); 100} 101 102/*% 103 * Remove a waiting (or ready to run) function from the queue. 104 */ 105int 106evUnwait(evContext opaqueCtx, evWaitID id) { 107 evContext_p *ctx = opaqueCtx.opaque; 108 evWait *this, *prev; 109 evWaitList *wl; 110 int found = 0; 111 112 this = id.opaque; 113 INSIST(this != NULL); 114 wl = evGetWaitList(ctx, this->tag, 0); 115 if (wl != NULL) { 116 for (prev = NULL, this = wl->first; 117 this != NULL; 118 prev = this, this = this->next) 119 if (this == (evWait *)id.opaque) { 120 found = 1; 121 if (prev != NULL) 122 prev->next = this->next; 123 else 124 wl->first = this->next; 125 if (wl->last == this) 126 wl->last = prev; 127 if (wl->first == NULL) 128 evFreeWaitList(ctx, wl); 129 break; 130 } 131 } 132 133 if (!found) { 134 /* Maybe it's done */ 135 for (prev = NULL, this = ctx->waitDone.first; 136 this != NULL; 137 prev = this, this = this->next) 138 if (this == (evWait *)id.opaque) { 139 found = 1; 140 if (prev != NULL) 141 prev->next = this->next; 142 else 143 ctx->waitDone.first = this->next; 144 if (ctx->waitDone.last == this) 145 ctx->waitDone.last = prev; 146 break; 147 } 148 } 149 150 if (!found) { 151 errno = ENOENT; 152 return (-1); 153 } 154 155 FREE(this); 156 157 if (ctx->debug >= 9) 158 print_waits(ctx); 159 160 return (0); 161} 162 163int 164evDefer(evContext opaqueCtx, evWaitFunc func, void *uap) { 165 evContext_p *ctx = opaqueCtx.opaque; 166 evWait *new; 167 168 OKNEW(new); 169 new->func = func; 170 new->uap = uap; 171 new->tag = NULL; 172 new->next = NULL; 173 if (ctx->waitDone.last != NULL) 174 ctx->waitDone.last->next = new; 175 else 176 ctx->waitDone.first = new; 177 ctx->waitDone.last = new; 178 if (ctx->debug >= 9) 179 print_waits(ctx); 180 return (0); 181} 182 183/* Private. */ 184 185static void 186print_waits(evContext_p *ctx) { 187 evWaitList *wl; 188 evWait *this; 189 190 evPrintf(ctx, 9, "wait waiting:\n"); 191 for (wl = ctx->waitLists; wl != NULL; wl = wl->next) { 192 INSIST(wl->first != NULL); 193 evPrintf(ctx, 9, " tag %p:", wl->first->tag); 194 for (this = wl->first; this != NULL; this = this->next) 195 evPrintf(ctx, 9, " %p", this); 196 evPrintf(ctx, 9, "\n"); 197 } 198 evPrintf(ctx, 9, "wait done:"); 199 for (this = ctx->waitDone.first; this != NULL; this = this->next) 200 evPrintf(ctx, 9, " %p", this); 201 evPrintf(ctx, 9, "\n"); 202} 203 204static evWaitList * 205evNewWaitList(evContext_p *ctx) { 206 evWaitList *new; 207 208 NEW(new); 209 if (new == NULL) 210 return (NULL); 211 new->first = new->last = NULL; 212 new->prev = NULL; 213 new->next = ctx->waitLists; 214 if (new->next != NULL) 215 new->next->prev = new; 216 ctx->waitLists = new; 217 return (new); 218} 219 220static void 221evFreeWaitList(evContext_p *ctx, evWaitList *this) { 222 223 INSIST(this != NULL); 224 225 if (this->prev != NULL) 226 this->prev->next = this->next; 227 else 228 ctx->waitLists = this->next; 229 if (this->next != NULL) 230 this->next->prev = this->prev; 231 FREE(this); 232} 233 234static evWaitList * 235evGetWaitList(evContext_p *ctx, const void *tag, int should_create) { 236 evWaitList *this; 237 238 for (this = ctx->waitLists; this != NULL; this = this->next) { 239 if (this->first != NULL && this->first->tag == tag) 240 break; 241 } 242 if (this == NULL && should_create) 243 this = evNewWaitList(ctx); 244 return (this); 245} 246 247/*! \file */ 248