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.1.4.4 2004/12/09 04:07:15 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"
50 static int pselect(int, void *, void *, void *,
60 evCreate(evContext *opaqueCtx) {
63 /* Make sure the memory heap is initialized. */
64 if (meminit(0, 0) < 0 && errno != EEXIST)
78 INIT_LIST(ctx->accepts);
82 FD_ZERO(&ctx->rdNext);
83 FD_ZERO(&ctx->wrNext);
84 FD_ZERO(&ctx->exNext);
85 FD_ZERO(&ctx->nonblockBefore);
88 ctx->fdCount = 0; /* Invalidate {rd,wr,ex}Last. */
89 ctx->highestFD = FD_SETSIZE - 1;
90 #ifdef EVENTLIB_TIME_CHECKS
93 memset(ctx->fdTable, 0, sizeof ctx->fdTable);
101 ctx->lastEventTime = evNowTime();
102 #ifdef EVENTLIB_TIME_CHECKS
103 ctx->lastSelectTime = ctx->lastEventTime;
105 ctx->timers = evCreateTimers(ctx);
106 if (ctx->timers == NULL)
110 ctx->waitLists = NULL;
111 ctx->waitDone.first = ctx->waitDone.last = NULL;
112 ctx->waitDone.prev = ctx->waitDone.next = NULL;
114 opaqueCtx->opaque = ctx;
119 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
120 evContext_p *ctx = opaqueCtx.opaque;
123 ctx->output = output;
127 evDestroy(evContext opaqueCtx) {
128 evContext_p *ctx = opaqueCtx.opaque;
129 int revs = 424242; /* Doug Adams. */
130 evWaitList *this_wl, *next_wl;
131 evWait *this_wait, *next_wait;
134 while (revs-- > 0 && ctx->conns != NULL) {
137 id.opaque = ctx->conns;
138 (void) evCancelConn(opaqueCtx, id);
143 while (revs-- > 0 && ctx->streams != NULL) {
146 id.opaque = ctx->streams;
147 (void) evCancelRW(opaqueCtx, id);
151 while (revs-- > 0 && ctx->files != NULL) {
154 id.opaque = ctx->files;
155 (void) evDeselectFD(opaqueCtx, id);
160 evDestroyTimers(ctx);
163 for (this_wl = ctx->waitLists;
164 revs-- > 0 && this_wl != NULL;
166 next_wl = this_wl->next;
167 for (this_wait = this_wl->first;
168 revs-- > 0 && this_wait != NULL;
169 this_wait = next_wait) {
170 next_wait = this_wait->next;
175 for (this_wait = ctx->waitDone.first;
176 revs-- > 0 && this_wait != NULL;
177 this_wait = next_wait) {
178 next_wait = this_wait->next;
187 evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
188 evContext_p *ctx = opaqueCtx.opaque;
189 struct timespec nextTime;
192 int x, pselect_errno, timerPast;
193 #ifdef EVENTLIB_TIME_CHECKS
194 struct timespec interval;
197 /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
198 x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
202 /* Get the time of day. We'll do this again after select() blocks. */
203 ctx->lastEventTime = evNowTime();
206 /* Finished accept()'s do not require a select(). */
207 if (!EMPTY(ctx->accepts)) {
210 new->u.accept.this = HEAD(ctx->accepts);
211 UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
212 opaqueEv->opaque = new;
216 /* Stream IO does not require a select(). */
217 if (ctx->strDone != NULL) {
220 new->u.stream.this = ctx->strDone;
221 ctx->strDone = ctx->strDone->nextDone;
222 if (ctx->strDone == NULL)
224 opaqueEv->opaque = new;
228 /* Waits do not require a select(). */
229 if (ctx->waitDone.first != NULL) {
232 new->u.wait.this = ctx->waitDone.first;
233 ctx->waitDone.first = ctx->waitDone.first->next;
234 if (ctx->waitDone.first == NULL)
235 ctx->waitDone.last = NULL;
236 opaqueEv->opaque = new;
240 /* Get the status and content of the next timer. */
241 if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
242 nextTime = nextTimer->due;
243 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
245 timerPast = 0; /* Make gcc happy. */
247 evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
248 if (ctx->fdCount == 0) {
249 static const struct timespec NoTime = {0, 0L};
250 enum { JustPoll, Block, Timer } m;
251 struct timespec t, *tp;
253 /* Are there any events at all? */
254 if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
257 /* Figure out what select()'s timeout parameter should be. */
258 if ((options & EV_POLL) != 0) {
262 } else if (nextTimer == NULL) {
266 } else if (timerPast) {
272 /* ``t'' filled in later. */
275 #ifdef EVENTLIB_TIME_CHECKS
276 if (ctx->debug > 0) {
277 interval = evSubTime(ctx->lastEventTime,
278 ctx->lastSelectTime);
279 if (interval.tv_sec > 0 || interval.tv_nsec > 0)
281 "time between pselect() %u.%09u count %d\n",
282 interval.tv_sec, interval.tv_nsec,
287 /* XXX need to copy only the bits we are using. */
288 ctx->rdLast = ctx->rdNext;
289 ctx->wrLast = ctx->wrNext;
290 ctx->exLast = ctx->exNext;
294 t = evSubTime(nextTime, ctx->lastEventTime);
298 "pselect(%d, 0x%lx, 0x%lx, 0x%lx, %ld.%09ld)\n",
300 (u_long)ctx->rdLast.fds_bits[0],
301 (u_long)ctx->wrLast.fds_bits[0],
302 (u_long)ctx->exLast.fds_bits[0],
303 tp ? (long)tp->tv_sec : -1L,
304 tp ? tp->tv_nsec : -1);
306 /* XXX should predict system's earliness and adjust. */
307 x = pselect(ctx->fdMax+1,
308 &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
310 pselect_errno = errno;
312 evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
313 x, (x == -1) ? strerror(errno) : "none");
315 /* Anything but a poll can change the time. */
317 ctx->lastEventTime = evNowTime();
319 /* Select() likes to finish about 10ms early. */
320 } while (x == 0 && m == Timer &&
321 evCmpTime(ctx->lastEventTime, nextTime) < 0);
322 #ifdef EVENTLIB_TIME_CHECKS
323 ctx->lastSelectTime = ctx->lastEventTime;
326 if (pselect_errno == EINTR) {
327 if ((options & EV_NULL) != 0)
332 opaqueEv->opaque = new;
335 if (pselect_errno == EBADF) {
336 for (x = 0; x <= ctx->fdMax; x++) {
339 if (FD_ISSET(x, &ctx->rdNext) == 0 &&
340 FD_ISSET(x, &ctx->wrNext) == 0 &&
341 FD_ISSET(x, &ctx->exNext) == 0)
343 if (fstat(x, &sb) == -1 &&
345 evPrintf(ctx, 1, "EBADF: %d\n",
350 EV_ERR(pselect_errno);
352 if (x == 0 && (nextTimer == NULL || !timerPast) &&
356 #ifdef EVENTLIB_TIME_CHECKS
357 ctx->lastFdCount = x;
360 INSIST(nextTimer || ctx->fdCount);
362 /* Timers go first since we'd like them to be accurate. */
363 if (nextTimer && !timerPast) {
364 /* Has anything happened since we blocked? */
365 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
367 if (nextTimer && timerPast) {
370 new->u.timer.this = nextTimer;
371 opaqueEv->opaque = new;
375 /* No timers, so there should be a ready file descriptor. */
377 while (ctx->fdCount > 0) {
381 if (ctx->fdNext == NULL) {
384 * Hitting the end twice means that the last
385 * select() found some FD's which have since
388 * On some systems, the count returned by
389 * selects is the total number of bits in
390 * all masks that are set, and on others it's
391 * the number of fd's that have some bit set,
392 * and on others, it's just broken. We
393 * always assume that it's the number of
394 * bits set in all masks, because that's what
395 * the man page says it should do, and
396 * the worst that can happen is we do an
402 ctx->fdNext = ctx->files;
405 ctx->fdNext = fid->next;
409 if (FD_ISSET(fd, &ctx->rdLast))
410 eventmask |= EV_READ;
411 if (FD_ISSET(fd, &ctx->wrLast))
412 eventmask |= EV_WRITE;
413 if (FD_ISSET(fd, &ctx->exLast))
414 eventmask |= EV_EXCEPT;
415 eventmask &= fid->eventmask;
416 if (eventmask != 0) {
417 if ((eventmask & EV_READ) != 0) {
418 FD_CLR(fd, &ctx->rdLast);
421 if ((eventmask & EV_WRITE) != 0) {
422 FD_CLR(fd, &ctx->wrLast);
425 if ((eventmask & EV_EXCEPT) != 0) {
426 FD_CLR(fd, &ctx->exLast);
431 new->u.file.this = fid;
432 new->u.file.eventmask = eventmask;
433 opaqueEv->opaque = new;
437 if (ctx->fdCount < 0) {
439 * select()'s count is off on a number of systems, and
440 * can result in fdCount < 0.
442 evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
446 /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
451 evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
452 evContext_p *ctx = opaqueCtx.opaque;
453 evEvent_p *ev = opaqueEv.opaque;
454 #ifdef EVENTLIB_TIME_CHECKS
456 struct timespec start_time;
457 struct timespec interval;
460 #ifdef EVENTLIB_TIME_CHECKS
462 start_time = evNowTime();
467 evAccept *this = ev->u.accept.this;
470 "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
471 this->conn->fd, this->fd,
472 this->conn->func, this->conn->uap);
473 errno = this->ioErrno;
474 (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
475 &this->la, this->lalen,
476 &this->ra, this->ralen);
477 #ifdef EVENTLIB_TIME_CHECKS
478 func = this->conn->func;
483 evFile *this = ev->u.file.this;
484 int eventmask = ev->u.file.eventmask;
487 "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
488 this->fd, this->eventmask, this->func, this->uap);
489 (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
490 #ifdef EVENTLIB_TIME_CHECKS
496 evStream *this = ev->u.stream.this;
499 "Dispatch.Stream: fd %d, func %p, uap %p\n",
500 this->fd, this->func, this->uap);
501 errno = this->ioErrno;
502 (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
503 #ifdef EVENTLIB_TIME_CHECKS
509 evTimer *this = ev->u.timer.this;
511 evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
512 this->func, this->uap);
513 (this->func)(opaqueCtx, this->uap, this->due, this->inter);
514 #ifdef EVENTLIB_TIME_CHECKS
520 evWait *this = ev->u.wait.this;
523 "Dispatch.Wait: tag %p, func %p, uap %p\n",
524 this->tag, this->func, this->uap);
525 (this->func)(opaqueCtx, this->uap, this->tag);
526 #ifdef EVENTLIB_TIME_CHECKS
533 #ifdef EVENTLIB_TIME_CHECKS
542 #ifdef EVENTLIB_TIME_CHECKS
543 if (ctx->debug > 0) {
544 interval = evSubTime(evNowTime(), start_time);
546 * Complain if it took longer than 50 milliseconds.
548 * We call getuid() to make an easy to find mark in a kernel
551 if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
553 "dispatch interval %u.%09u uid %d type %d func %p\n",
554 interval.tv_sec, interval.tv_nsec,
555 getuid(), ev->type, func);
559 evDrop(opaqueCtx, opaqueEv);
564 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
565 evContext_p *ctx = opaqueCtx.opaque;
566 evEvent_p *ev = opaqueEv.opaque;
570 FREE(ev->u.accept.this);
580 id.opaque = ev->u.stream.this;
581 (void) evCancelRW(opaqueCtx, id);
585 evTimer *this = ev->u.timer.this;
588 /* Check to see whether the user func cleared the timer. */
589 if (heap_element(ctx->timers, this->index) != this) {
590 evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
594 * Timer is still there. Delete it if it has expired,
595 * otherwise set it according to its next interval.
597 if (this->inter.tv_sec == (time_t)0 &&
598 this->inter.tv_nsec == 0L) {
599 opaque.opaque = this;
600 (void) evClearTimer(opaqueCtx, opaque);
602 opaque.opaque = this;
603 (void) evResetTimer(opaqueCtx, opaque, this->func,
605 evAddTime((this->mode & EV_TMR_RATE) ?
614 FREE(ev->u.wait.this);
629 evMainLoop(evContext opaqueCtx) {
633 while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
634 if ((x = evDispatch(opaqueCtx, event)) < 0)
640 evHighestFD(evContext opaqueCtx) {
641 evContext_p *ctx = opaqueCtx.opaque;
643 return (ctx->highestFD);
647 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
651 if (ctx->output != NULL && ctx->debug >= level) {
652 vfprintf(ctx->output, fmt, ap);
659 evSetOption(evContext *opaqueCtx, const char *option, int value) {
660 /* evContext_p *ctx = opaqueCtx->opaque; */
664 #ifndef CLOCK_MONOTONIC
668 #ifdef CLOCK_MONOTONIC
669 if (strcmp(option, "monotime") == 0) {
670 if (opaqueCtx != NULL)
672 if (value == 0 || value == 1) {
673 __evOptMonoTime = value;
686 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
687 /* evContext_p *ctx = opaqueCtx->opaque; */
690 #ifndef CLOCK_MONOTONIC
695 #ifdef CLOCK_MONOTONIC
696 if (strcmp(option, "monotime") == 0) {
697 if (opaqueCtx != NULL)
699 *value = __evOptMonoTime;
708 /* XXX needs to move to the porting library. */
710 pselect(int nfds, void *rfds, void *wfds, void *efds,
711 struct timespec *tsp,
712 const sigset_t *sigmask)
714 struct timeval tv, *tvp;
720 tv = evTimeVal(*tsp);
724 sigprocmask(SIG_SETMASK, sigmask, &sigs);
725 n = select(nfds, rfds, wfds, efds, tvp);
727 sigprocmask(SIG_SETMASK, &sigs, NULL);
729 *tsp = evTimeSpec(tv);