2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1995-1999 by Internet Software Consortium
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.
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.
18 /* eventlib.c - implement glue for the eventlib
19 * vix 09sep95 [initial]
22 #if !defined(LINT) && !defined(CODECENTER)
23 static const char rcsid[] = "$Id: eventlib.c,v 1.2.2.3 2004/03/17 01:54:22 marka Exp $";
26 #include "port_before.h"
27 #include "fd_setsize.h"
29 #include <sys/types.h>
39 #include <isc/eventlib.h>
40 #include <isc/assertions.h>
41 #include "eventlib_p.h"
43 #include "port_after.h"
48 static int pselect(int, void *, void *, void *,
56 evCreate(evContext *opaqueCtx) {
59 /* Make sure the memory heap is initialized. */
60 if (meminit(0, 0) < 0 && errno != EEXIST)
74 INIT_LIST(ctx->accepts);
78 FD_ZERO(&ctx->rdNext);
79 FD_ZERO(&ctx->wrNext);
80 FD_ZERO(&ctx->exNext);
81 FD_ZERO(&ctx->nonblockBefore);
84 ctx->fdCount = 0; /* Invalidate {rd,wr,ex}Last. */
85 ctx->highestFD = FD_SETSIZE - 1;
86 #ifdef EVENTLIB_TIME_CHECKS
89 memset(ctx->fdTable, 0, sizeof ctx->fdTable);
97 ctx->lastEventTime = evNowTime();
98 #ifdef EVENTLIB_TIME_CHECKS
99 ctx->lastSelectTime = ctx->lastEventTime;
101 ctx->timers = evCreateTimers(ctx);
102 if (ctx->timers == NULL)
106 ctx->waitLists = NULL;
107 ctx->waitDone.first = ctx->waitDone.last = NULL;
108 ctx->waitDone.prev = ctx->waitDone.next = NULL;
110 opaqueCtx->opaque = ctx;
115 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
116 evContext_p *ctx = opaqueCtx.opaque;
119 ctx->output = output;
123 evDestroy(evContext opaqueCtx) {
124 evContext_p *ctx = opaqueCtx.opaque;
125 int revs = 424242; /* Doug Adams. */
126 evWaitList *this_wl, *next_wl;
127 evWait *this_wait, *next_wait;
130 while (revs-- > 0 && ctx->conns != NULL) {
133 id.opaque = ctx->conns;
134 (void) evCancelConn(opaqueCtx, id);
139 while (revs-- > 0 && ctx->streams != NULL) {
142 id.opaque = ctx->streams;
143 (void) evCancelRW(opaqueCtx, id);
147 while (revs-- > 0 && ctx->files != NULL) {
150 id.opaque = ctx->files;
151 (void) evDeselectFD(opaqueCtx, id);
156 evDestroyTimers(ctx);
159 for (this_wl = ctx->waitLists;
160 revs-- > 0 && this_wl != NULL;
162 next_wl = this_wl->next;
163 for (this_wait = this_wl->first;
164 revs-- > 0 && this_wait != NULL;
165 this_wait = next_wait) {
166 next_wait = this_wait->next;
171 for (this_wait = ctx->waitDone.first;
172 revs-- > 0 && this_wait != NULL;
173 this_wait = next_wait) {
174 next_wait = this_wait->next;
183 evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
184 evContext_p *ctx = opaqueCtx.opaque;
185 struct timespec nextTime;
188 int x, pselect_errno, timerPast;
189 #ifdef EVENTLIB_TIME_CHECKS
190 struct timespec interval;
193 /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
194 x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
198 /* Get the time of day. We'll do this again after select() blocks. */
199 ctx->lastEventTime = evNowTime();
202 /* Finished accept()'s do not require a select(). */
203 if (!EMPTY(ctx->accepts)) {
206 new->u.accept.this = HEAD(ctx->accepts);
207 UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
208 opaqueEv->opaque = new;
212 /* Stream IO does not require a select(). */
213 if (ctx->strDone != NULL) {
216 new->u.stream.this = ctx->strDone;
217 ctx->strDone = ctx->strDone->nextDone;
218 if (ctx->strDone == NULL)
220 opaqueEv->opaque = new;
224 /* Waits do not require a select(). */
225 if (ctx->waitDone.first != NULL) {
228 new->u.wait.this = ctx->waitDone.first;
229 ctx->waitDone.first = ctx->waitDone.first->next;
230 if (ctx->waitDone.first == NULL)
231 ctx->waitDone.last = NULL;
232 opaqueEv->opaque = new;
236 /* Get the status and content of the next timer. */
237 if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
238 nextTime = nextTimer->due;
239 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
241 timerPast = 0; /* Make gcc happy. */
243 evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
244 if (ctx->fdCount == 0) {
245 static const struct timespec NoTime = {0, 0L};
246 enum { JustPoll, Block, Timer } m;
247 struct timespec t, *tp;
249 /* Are there any events at all? */
250 if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
253 /* Figure out what select()'s timeout parameter should be. */
254 if ((options & EV_POLL) != 0) {
258 } else if (nextTimer == NULL) {
262 } else if (timerPast) {
268 /* ``t'' filled in later. */
271 #ifdef EVENTLIB_TIME_CHECKS
272 if (ctx->debug > 0) {
273 interval = evSubTime(ctx->lastEventTime,
274 ctx->lastSelectTime);
275 if (interval.tv_sec > 0 || interval.tv_nsec > 0)
277 "time between pselect() %u.%09u count %d\n",
278 interval.tv_sec, interval.tv_nsec,
283 /* XXX need to copy only the bits we are using. */
284 ctx->rdLast = ctx->rdNext;
285 ctx->wrLast = ctx->wrNext;
286 ctx->exLast = ctx->exNext;
290 t = evSubTime(nextTime, ctx->lastEventTime);
294 "pselect(%d, 0x%lx, 0x%lx, 0x%lx, %ld.%09ld)\n",
296 (u_long)ctx->rdLast.fds_bits[0],
297 (u_long)ctx->wrLast.fds_bits[0],
298 (u_long)ctx->exLast.fds_bits[0],
299 tp ? (long)tp->tv_sec : -1L,
300 tp ? tp->tv_nsec : -1);
302 /* XXX should predict system's earliness and adjust. */
303 x = pselect(ctx->fdMax+1,
304 &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
306 pselect_errno = errno;
308 evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
309 x, (x == -1) ? strerror(errno) : "none");
311 /* Anything but a poll can change the time. */
313 ctx->lastEventTime = evNowTime();
315 /* Select() likes to finish about 10ms early. */
316 } while (x == 0 && m == Timer &&
317 evCmpTime(ctx->lastEventTime, nextTime) < 0);
318 #ifdef EVENTLIB_TIME_CHECKS
319 ctx->lastSelectTime = ctx->lastEventTime;
322 if (pselect_errno == EINTR) {
323 if ((options & EV_NULL) != 0)
328 opaqueEv->opaque = new;
331 if (pselect_errno == EBADF) {
332 for (x = 0; x <= ctx->fdMax; x++) {
335 if (FD_ISSET(x, &ctx->rdNext) == 0 &&
336 FD_ISSET(x, &ctx->wrNext) == 0 &&
337 FD_ISSET(x, &ctx->exNext) == 0)
339 if (fstat(x, &sb) == -1 &&
341 evPrintf(ctx, 1, "EBADF: %d\n",
346 EV_ERR(pselect_errno);
348 if (x == 0 && (nextTimer == NULL || !timerPast) &&
352 #ifdef EVENTLIB_TIME_CHECKS
353 ctx->lastFdCount = x;
356 INSIST(nextTimer || ctx->fdCount);
358 /* Timers go first since we'd like them to be accurate. */
359 if (nextTimer && !timerPast) {
360 /* Has anything happened since we blocked? */
361 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
363 if (nextTimer && timerPast) {
366 new->u.timer.this = nextTimer;
367 opaqueEv->opaque = new;
371 /* No timers, so there should be a ready file descriptor. */
373 while (ctx->fdCount > 0) {
377 if (ctx->fdNext == NULL) {
380 * Hitting the end twice means that the last
381 * select() found some FD's which have since
384 * On some systems, the count returned by
385 * selects is the total number of bits in
386 * all masks that are set, and on others it's
387 * the number of fd's that have some bit set,
388 * and on others, it's just broken. We
389 * always assume that it's the number of
390 * bits set in all masks, because that's what
391 * the man page says it should do, and
392 * the worst that can happen is we do an
398 ctx->fdNext = ctx->files;
401 ctx->fdNext = fid->next;
405 if (FD_ISSET(fd, &ctx->rdLast))
406 eventmask |= EV_READ;
407 if (FD_ISSET(fd, &ctx->wrLast))
408 eventmask |= EV_WRITE;
409 if (FD_ISSET(fd, &ctx->exLast))
410 eventmask |= EV_EXCEPT;
411 eventmask &= fid->eventmask;
412 if (eventmask != 0) {
413 if ((eventmask & EV_READ) != 0) {
414 FD_CLR(fd, &ctx->rdLast);
417 if ((eventmask & EV_WRITE) != 0) {
418 FD_CLR(fd, &ctx->wrLast);
421 if ((eventmask & EV_EXCEPT) != 0) {
422 FD_CLR(fd, &ctx->exLast);
427 new->u.file.this = fid;
428 new->u.file.eventmask = eventmask;
429 opaqueEv->opaque = new;
433 if (ctx->fdCount < 0) {
435 * select()'s count is off on a number of systems, and
436 * can result in fdCount < 0.
438 evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
442 /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
447 evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
448 evContext_p *ctx = opaqueCtx.opaque;
449 evEvent_p *ev = opaqueEv.opaque;
450 #ifdef EVENTLIB_TIME_CHECKS
452 struct timespec start_time;
453 struct timespec interval;
456 #ifdef EVENTLIB_TIME_CHECKS
458 start_time = evNowTime();
463 evAccept *this = ev->u.accept.this;
466 "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
467 this->conn->fd, this->fd,
468 this->conn->func, this->conn->uap);
469 errno = this->ioErrno;
470 (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
471 &this->la, this->lalen,
472 &this->ra, this->ralen);
473 #ifdef EVENTLIB_TIME_CHECKS
474 func = this->conn->func;
479 evFile *this = ev->u.file.this;
480 int eventmask = ev->u.file.eventmask;
483 "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
484 this->fd, this->eventmask, this->func, this->uap);
485 (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
486 #ifdef EVENTLIB_TIME_CHECKS
492 evStream *this = ev->u.stream.this;
495 "Dispatch.Stream: fd %d, func %p, uap %p\n",
496 this->fd, this->func, this->uap);
497 errno = this->ioErrno;
498 (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
499 #ifdef EVENTLIB_TIME_CHECKS
505 evTimer *this = ev->u.timer.this;
507 evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
508 this->func, this->uap);
509 (this->func)(opaqueCtx, this->uap, this->due, this->inter);
510 #ifdef EVENTLIB_TIME_CHECKS
516 evWait *this = ev->u.wait.this;
519 "Dispatch.Wait: tag %p, func %p, uap %p\n",
520 this->tag, this->func, this->uap);
521 (this->func)(opaqueCtx, this->uap, this->tag);
522 #ifdef EVENTLIB_TIME_CHECKS
529 #ifdef EVENTLIB_TIME_CHECKS
538 #ifdef EVENTLIB_TIME_CHECKS
539 if (ctx->debug > 0) {
540 interval = evSubTime(evNowTime(), start_time);
542 * Complain if it took longer than 50 milliseconds.
544 * We call getuid() to make an easy to find mark in a kernel
547 if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
549 "dispatch interval %u.%09u uid %d type %d func %p\n",
550 interval.tv_sec, interval.tv_nsec,
551 getuid(), ev->type, func);
555 evDrop(opaqueCtx, opaqueEv);
560 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
561 evContext_p *ctx = opaqueCtx.opaque;
562 evEvent_p *ev = opaqueEv.opaque;
566 FREE(ev->u.accept.this);
576 id.opaque = ev->u.stream.this;
577 (void) evCancelRW(opaqueCtx, id);
581 evTimer *this = ev->u.timer.this;
584 /* Check to see whether the user func cleared the timer. */
585 if (heap_element(ctx->timers, this->index) != this) {
586 evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
590 * Timer is still there. Delete it if it has expired,
591 * otherwise set it according to its next interval.
593 if (this->inter.tv_sec == (time_t)0 &&
594 this->inter.tv_nsec == 0L) {
595 opaque.opaque = this;
596 (void) evClearTimer(opaqueCtx, opaque);
598 opaque.opaque = this;
599 (void) evResetTimer(opaqueCtx, opaque, this->func,
601 evAddTime((this->mode & EV_TMR_RATE) ?
610 FREE(ev->u.wait.this);
625 evMainLoop(evContext opaqueCtx) {
629 while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
630 if ((x = evDispatch(opaqueCtx, event)) < 0)
636 evHighestFD(evContext opaqueCtx) {
637 evContext_p *ctx = opaqueCtx.opaque;
639 return (ctx->highestFD);
643 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
647 if (ctx->output != NULL && ctx->debug >= level) {
648 vfprintf(ctx->output, fmt, ap);
655 evSetOption(evContext *opaqueCtx, const char *option, int value) {
656 /* evContext_p *ctx = opaqueCtx->opaque; */
660 #ifndef CLOCK_MONOTONIC
664 #ifdef CLOCK_MONOTONIC
665 if (strcmp(option, "monotime") == 0) {
666 if (opaqueCtx != NULL)
668 if (value == 0 || value == 1) {
669 __evOptMonoTime = value;
682 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
683 /* evContext_p *ctx = opaqueCtx->opaque; */
686 #ifndef CLOCK_MONOTONIC
691 #ifdef CLOCK_MONOTONIC
692 if (strcmp(option, "monotime") == 0) {
693 if (opaqueCtx != NULL)
695 *value = __evOptMonoTime;
704 /* XXX needs to move to the porting library. */
706 pselect(int nfds, void *rfds, void *wfds, void *efds,
707 struct timespec *tsp,
708 const sigset_t *sigmask)
710 struct timeval tv, *tvp;
716 tv = evTimeVal(*tsp);
720 sigprocmask(SIG_SETMASK, sigmask, &sigs);
721 n = select(nfds, rfds, wfds, efds, tvp);
723 sigprocmask(SIG_SETMASK, &sigs, NULL);
725 *tsp = evTimeSpec(tv);