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) 23 static 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 39 static void print_waits(evContext_p *ctx); 40 static evWaitList * evNewWaitList(evContext_p *); 41 static void evFreeWaitList(evContext_p *, evWaitList *); 42 static evWaitList * evGetWaitList(evContext_p *, const void *, int); 43 44 45 /* Public. */ 46 47 /*% 48 * Enter a new wait function on the queue. 49 */ 50 int 51 evWaitFor(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 */ 78 int 79 evDo(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 */ 105 int 106 evUnwait(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 163 int 164 evDefer(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 185 static void 186 print_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 204 static evWaitList * 205 evNewWaitList(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 220 static void 221 evFreeWaitList(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 234 static evWaitList * 235 evGetWaitList(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