BIND - Update BIND to 9.5.2
[dragonfly.git] / contrib / bind-9.5.2 / lib / bind / isc / eventlib.c
blobbe4a7848b99fa3ee4b128e2afec61a3aae2024cc
1 /*
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.10 2006/03/09 23:57:56 marka Exp $";
24 #endif
26 #include "port_before.h"
27 #include "fd_setsize.h"
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <sys/stat.h>
32 #ifdef SOLARIS2
33 #include <limits.h>
34 #endif /* SOLARIS2 */
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <unistd.h>
42 #include <isc/eventlib.h>
43 #include <isc/assertions.h>
44 #include "eventlib_p.h"
46 #include "port_after.h"
48 int __evOptMonoTime;
50 #ifdef USE_POLL
51 #define pselect Pselect
52 #endif /* USE_POLL */
54 /* Forward. */
56 #if defined(NEED_PSELECT) || defined(USE_POLL)
57 static int pselect(int, void *, void *, void *,
58 struct timespec *,
59 const sigset_t *);
60 #endif
62 int __evOptMonoTime;
64 /* Public. */
66 int
67 evCreate(evContext *opaqueCtx) {
68 evContext_p *ctx;
70 /* Make sure the memory heap is initialized. */
71 if (meminit(0, 0) < 0 && errno != EEXIST)
72 return (-1);
74 OKNEW(ctx);
76 /* Global. */
77 ctx->cur = NULL;
79 /* Debugging. */
80 ctx->debug = 0;
81 ctx->output = NULL;
83 /* Connections. */
84 ctx->conns = NULL;
85 INIT_LIST(ctx->accepts);
87 /* Files. */
88 ctx->files = NULL;
89 #ifdef USE_POLL
90 ctx->pollfds = NULL;
91 ctx->maxnfds = 0;
92 ctx->firstfd = 0;
93 emulMaskInit(ctx, rdLast, EV_READ, 1);
94 emulMaskInit(ctx, rdNext, EV_READ, 0);
95 emulMaskInit(ctx, wrLast, EV_WRITE, 1);
96 emulMaskInit(ctx, wrNext, EV_WRITE, 0);
97 emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
98 emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
99 emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
100 #endif /* USE_POLL */
101 FD_ZERO(&ctx->rdNext);
102 FD_ZERO(&ctx->wrNext);
103 FD_ZERO(&ctx->exNext);
104 FD_ZERO(&ctx->nonblockBefore);
105 ctx->fdMax = -1;
106 ctx->fdNext = NULL;
107 ctx->fdCount = 0; /*%< Invalidate {rd,wr,ex}Last. */
108 #ifndef USE_POLL
109 ctx->highestFD = FD_SETSIZE - 1;
110 memset(ctx->fdTable, 0, sizeof ctx->fdTable);
111 #else
112 ctx->highestFD = INT_MAX / sizeof(struct pollfd);
113 ctx->fdTable = NULL;
114 #endif /* USE_POLL */
115 #ifdef EVENTLIB_TIME_CHECKS
116 ctx->lastFdCount = 0;
117 #endif
119 /* Streams. */
120 ctx->streams = NULL;
121 ctx->strDone = NULL;
122 ctx->strLast = NULL;
124 /* Timers. */
125 ctx->lastEventTime = evNowTime();
126 #ifdef EVENTLIB_TIME_CHECKS
127 ctx->lastSelectTime = ctx->lastEventTime;
128 #endif
129 ctx->timers = evCreateTimers(ctx);
130 if (ctx->timers == NULL)
131 return (-1);
133 /* Waits. */
134 ctx->waitLists = NULL;
135 ctx->waitDone.first = ctx->waitDone.last = NULL;
136 ctx->waitDone.prev = ctx->waitDone.next = NULL;
138 opaqueCtx->opaque = ctx;
139 return (0);
142 void
143 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
144 evContext_p *ctx = opaqueCtx.opaque;
146 ctx->debug = level;
147 ctx->output = output;
151 evDestroy(evContext opaqueCtx) {
152 evContext_p *ctx = opaqueCtx.opaque;
153 int revs = 424242; /*%< Doug Adams. */
154 evWaitList *this_wl, *next_wl;
155 evWait *this_wait, *next_wait;
157 /* Connections. */
158 while (revs-- > 0 && ctx->conns != NULL) {
159 evConnID id;
161 id.opaque = ctx->conns;
162 (void) evCancelConn(opaqueCtx, id);
164 INSIST(revs >= 0);
166 /* Streams. */
167 while (revs-- > 0 && ctx->streams != NULL) {
168 evStreamID id;
170 id.opaque = ctx->streams;
171 (void) evCancelRW(opaqueCtx, id);
174 /* Files. */
175 while (revs-- > 0 && ctx->files != NULL) {
176 evFileID id;
178 id.opaque = ctx->files;
179 (void) evDeselectFD(opaqueCtx, id);
181 INSIST(revs >= 0);
183 /* Timers. */
184 evDestroyTimers(ctx);
186 /* Waits. */
187 for (this_wl = ctx->waitLists;
188 revs-- > 0 && this_wl != NULL;
189 this_wl = next_wl) {
190 next_wl = this_wl->next;
191 for (this_wait = this_wl->first;
192 revs-- > 0 && this_wait != NULL;
193 this_wait = next_wait) {
194 next_wait = this_wait->next;
195 FREE(this_wait);
197 FREE(this_wl);
199 for (this_wait = ctx->waitDone.first;
200 revs-- > 0 && this_wait != NULL;
201 this_wait = next_wait) {
202 next_wait = this_wait->next;
203 FREE(this_wait);
206 FREE(ctx);
207 return (0);
211 evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
212 evContext_p *ctx = opaqueCtx.opaque;
213 struct timespec nextTime;
214 evTimer *nextTimer;
215 evEvent_p *new;
216 int x, pselect_errno, timerPast;
217 #ifdef EVENTLIB_TIME_CHECKS
218 struct timespec interval;
219 #endif
221 /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
222 x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
223 if (x != 1)
224 EV_ERR(EINVAL);
226 /* Get the time of day. We'll do this again after select() blocks. */
227 ctx->lastEventTime = evNowTime();
229 again:
230 /* Finished accept()'s do not require a select(). */
231 if (!EMPTY(ctx->accepts)) {
232 OKNEW(new);
233 new->type = Accept;
234 new->u.accept.this = HEAD(ctx->accepts);
235 UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
236 opaqueEv->opaque = new;
237 return (0);
240 /* Stream IO does not require a select(). */
241 if (ctx->strDone != NULL) {
242 OKNEW(new);
243 new->type = Stream;
244 new->u.stream.this = ctx->strDone;
245 ctx->strDone = ctx->strDone->nextDone;
246 if (ctx->strDone == NULL)
247 ctx->strLast = NULL;
248 opaqueEv->opaque = new;
249 return (0);
252 /* Waits do not require a select(). */
253 if (ctx->waitDone.first != NULL) {
254 OKNEW(new);
255 new->type = Wait;
256 new->u.wait.this = ctx->waitDone.first;
257 ctx->waitDone.first = ctx->waitDone.first->next;
258 if (ctx->waitDone.first == NULL)
259 ctx->waitDone.last = NULL;
260 opaqueEv->opaque = new;
261 return (0);
264 /* Get the status and content of the next timer. */
265 if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
266 nextTime = nextTimer->due;
267 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
268 } else
269 timerPast = 0; /*%< Make gcc happy. */
270 evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
271 if (ctx->fdCount == 0) {
272 static const struct timespec NoTime = {0, 0L};
273 enum { JustPoll, Block, Timer } m;
274 struct timespec t, *tp;
276 /* Are there any events at all? */
277 if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
278 EV_ERR(ENOENT);
280 /* Figure out what select()'s timeout parameter should be. */
281 if ((options & EV_POLL) != 0) {
282 m = JustPoll;
283 t = NoTime;
284 tp = &t;
285 } else if (nextTimer == NULL) {
286 m = Block;
287 /* ``t'' unused. */
288 tp = NULL;
289 } else if (timerPast) {
290 m = JustPoll;
291 t = NoTime;
292 tp = &t;
293 } else {
294 m = Timer;
295 /* ``t'' filled in later. */
296 tp = &t;
298 #ifdef EVENTLIB_TIME_CHECKS
299 if (ctx->debug > 0) {
300 interval = evSubTime(ctx->lastEventTime,
301 ctx->lastSelectTime);
302 if (interval.tv_sec > 0 || interval.tv_nsec > 0)
303 evPrintf(ctx, 1,
304 "time between pselect() %u.%09u count %d\n",
305 interval.tv_sec, interval.tv_nsec,
306 ctx->lastFdCount);
308 #endif
309 do {
310 #ifndef USE_POLL
311 /* XXX need to copy only the bits we are using. */
312 ctx->rdLast = ctx->rdNext;
313 ctx->wrLast = ctx->wrNext;
314 ctx->exLast = ctx->exNext;
315 #else
317 * The pollfd structure uses separate fields for
318 * the input and output events (corresponding to
319 * the ??Next and ??Last fd sets), so there's no
320 * need to copy one to the other.
322 #endif /* USE_POLL */
323 if (m == Timer) {
324 INSIST(tp == &t);
325 t = evSubTime(nextTime, ctx->lastEventTime);
328 /* XXX should predict system's earliness and adjust. */
329 x = pselect(ctx->fdMax+1,
330 &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
331 tp, NULL);
332 pselect_errno = errno;
334 #ifndef USE_POLL
335 evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
336 x, (x == -1) ? strerror(errno) : "none");
337 #else
338 evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
339 x, (x == -1) ? strerror(errno) : "none");
340 #endif /* USE_POLL */
341 /* Anything but a poll can change the time. */
342 if (m != JustPoll)
343 ctx->lastEventTime = evNowTime();
345 /* Select() likes to finish about 10ms early. */
346 } while (x == 0 && m == Timer &&
347 evCmpTime(ctx->lastEventTime, nextTime) < 0);
348 #ifdef EVENTLIB_TIME_CHECKS
349 ctx->lastSelectTime = ctx->lastEventTime;
350 #endif
351 if (x < 0) {
352 if (pselect_errno == EINTR) {
353 if ((options & EV_NULL) != 0)
354 goto again;
355 OKNEW(new);
356 new->type = Null;
357 /* No data. */
358 opaqueEv->opaque = new;
359 return (0);
361 if (pselect_errno == EBADF) {
362 for (x = 0; x <= ctx->fdMax; x++) {
363 struct stat sb;
365 if (FD_ISSET(x, &ctx->rdNext) == 0 &&
366 FD_ISSET(x, &ctx->wrNext) == 0 &&
367 FD_ISSET(x, &ctx->exNext) == 0)
368 continue;
369 if (fstat(x, &sb) == -1 &&
370 errno == EBADF)
371 evPrintf(ctx, 1, "EBADF: %d\n",
374 abort();
376 EV_ERR(pselect_errno);
378 if (x == 0 && (nextTimer == NULL || !timerPast) &&
379 (options & EV_POLL))
380 EV_ERR(EWOULDBLOCK);
381 ctx->fdCount = x;
382 #ifdef EVENTLIB_TIME_CHECKS
383 ctx->lastFdCount = x;
384 #endif
386 INSIST(nextTimer || ctx->fdCount);
388 /* Timers go first since we'd like them to be accurate. */
389 if (nextTimer && !timerPast) {
390 /* Has anything happened since we blocked? */
391 timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
393 if (nextTimer && timerPast) {
394 OKNEW(new);
395 new->type = Timer;
396 new->u.timer.this = nextTimer;
397 opaqueEv->opaque = new;
398 return (0);
401 /* No timers, so there should be a ready file descriptor. */
402 x = 0;
403 while (ctx->fdCount > 0) {
404 evFile *fid;
405 int fd, eventmask;
407 if (ctx->fdNext == NULL) {
408 if (++x == 2) {
410 * Hitting the end twice means that the last
411 * select() found some FD's which have since
412 * been deselected.
414 * On some systems, the count returned by
415 * selects is the total number of bits in
416 * all masks that are set, and on others it's
417 * the number of fd's that have some bit set,
418 * and on others, it's just broken. We
419 * always assume that it's the number of
420 * bits set in all masks, because that's what
421 * the man page says it should do, and
422 * the worst that can happen is we do an
423 * extra select().
425 ctx->fdCount = 0;
426 break;
428 ctx->fdNext = ctx->files;
430 fid = ctx->fdNext;
431 ctx->fdNext = fid->next;
433 fd = fid->fd;
434 eventmask = 0;
435 if (FD_ISSET(fd, &ctx->rdLast))
436 eventmask |= EV_READ;
437 if (FD_ISSET(fd, &ctx->wrLast))
438 eventmask |= EV_WRITE;
439 if (FD_ISSET(fd, &ctx->exLast))
440 eventmask |= EV_EXCEPT;
441 eventmask &= fid->eventmask;
442 if (eventmask != 0) {
443 if ((eventmask & EV_READ) != 0) {
444 FD_CLR(fd, &ctx->rdLast);
445 ctx->fdCount--;
447 if ((eventmask & EV_WRITE) != 0) {
448 FD_CLR(fd, &ctx->wrLast);
449 ctx->fdCount--;
451 if ((eventmask & EV_EXCEPT) != 0) {
452 FD_CLR(fd, &ctx->exLast);
453 ctx->fdCount--;
455 OKNEW(new);
456 new->type = File;
457 new->u.file.this = fid;
458 new->u.file.eventmask = eventmask;
459 opaqueEv->opaque = new;
460 return (0);
463 if (ctx->fdCount < 0) {
465 * select()'s count is off on a number of systems, and
466 * can result in fdCount < 0.
468 evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
469 ctx->fdCount = 0;
472 /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
473 goto again;
477 evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
478 evContext_p *ctx = opaqueCtx.opaque;
479 evEvent_p *ev = opaqueEv.opaque;
480 #ifdef EVENTLIB_TIME_CHECKS
481 void *func;
482 struct timespec start_time;
483 struct timespec interval;
484 #endif
486 #ifdef EVENTLIB_TIME_CHECKS
487 if (ctx->debug > 0)
488 start_time = evNowTime();
489 #endif
490 ctx->cur = ev;
491 switch (ev->type) {
492 case Accept: {
493 evAccept *this = ev->u.accept.this;
495 evPrintf(ctx, 5,
496 "Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
497 this->conn->fd, this->fd,
498 this->conn->func, this->conn->uap);
499 errno = this->ioErrno;
500 (this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
501 &this->la, this->lalen,
502 &this->ra, this->ralen);
503 #ifdef EVENTLIB_TIME_CHECKS
504 func = this->conn->func;
505 #endif
506 break;
508 case File: {
509 evFile *this = ev->u.file.this;
510 int eventmask = ev->u.file.eventmask;
512 evPrintf(ctx, 5,
513 "Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
514 this->fd, this->eventmask, this->func, this->uap);
515 (this->func)(opaqueCtx, this->uap, this->fd, eventmask);
516 #ifdef EVENTLIB_TIME_CHECKS
517 func = this->func;
518 #endif
519 break;
521 case Stream: {
522 evStream *this = ev->u.stream.this;
524 evPrintf(ctx, 5,
525 "Dispatch.Stream: fd %d, func %p, uap %p\n",
526 this->fd, this->func, this->uap);
527 errno = this->ioErrno;
528 (this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
529 #ifdef EVENTLIB_TIME_CHECKS
530 func = this->func;
531 #endif
532 break;
534 case Timer: {
535 evTimer *this = ev->u.timer.this;
537 evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
538 this->func, this->uap);
539 (this->func)(opaqueCtx, this->uap, this->due, this->inter);
540 #ifdef EVENTLIB_TIME_CHECKS
541 func = this->func;
542 #endif
543 break;
545 case Wait: {
546 evWait *this = ev->u.wait.this;
548 evPrintf(ctx, 5,
549 "Dispatch.Wait: tag %p, func %p, uap %p\n",
550 this->tag, this->func, this->uap);
551 (this->func)(opaqueCtx, this->uap, this->tag);
552 #ifdef EVENTLIB_TIME_CHECKS
553 func = this->func;
554 #endif
555 break;
557 case Null: {
558 /* No work. */
559 #ifdef EVENTLIB_TIME_CHECKS
560 func = NULL;
561 #endif
562 break;
564 default: {
565 abort();
568 #ifdef EVENTLIB_TIME_CHECKS
569 if (ctx->debug > 0) {
570 interval = evSubTime(evNowTime(), start_time);
572 * Complain if it took longer than 50 milliseconds.
574 * We call getuid() to make an easy to find mark in a kernel
575 * trace.
577 if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
578 evPrintf(ctx, 1,
579 "dispatch interval %u.%09u uid %d type %d func %p\n",
580 interval.tv_sec, interval.tv_nsec,
581 getuid(), ev->type, func);
583 #endif
584 ctx->cur = NULL;
585 evDrop(opaqueCtx, opaqueEv);
586 return (0);
589 void
590 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
591 evContext_p *ctx = opaqueCtx.opaque;
592 evEvent_p *ev = opaqueEv.opaque;
594 switch (ev->type) {
595 case Accept: {
596 FREE(ev->u.accept.this);
597 break;
599 case File: {
600 /* No work. */
601 break;
603 case Stream: {
604 evStreamID id;
606 id.opaque = ev->u.stream.this;
607 (void) evCancelRW(opaqueCtx, id);
608 break;
610 case Timer: {
611 evTimer *this = ev->u.timer.this;
612 evTimerID opaque;
614 /* Check to see whether the user func cleared the timer. */
615 if (heap_element(ctx->timers, this->index) != this) {
616 evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
617 break;
620 * Timer is still there. Delete it if it has expired,
621 * otherwise set it according to its next interval.
623 if (this->inter.tv_sec == (time_t)0 &&
624 this->inter.tv_nsec == 0L) {
625 opaque.opaque = this;
626 (void) evClearTimer(opaqueCtx, opaque);
627 } else {
628 opaque.opaque = this;
629 (void) evResetTimer(opaqueCtx, opaque, this->func,
630 this->uap,
631 evAddTime((this->mode & EV_TMR_RATE) ?
632 this->due :
633 ctx->lastEventTime,
634 this->inter),
635 this->inter);
637 break;
639 case Wait: {
640 FREE(ev->u.wait.this);
641 break;
643 case Null: {
644 /* No work. */
645 break;
647 default: {
648 abort();
651 FREE(ev);
655 evMainLoop(evContext opaqueCtx) {
656 evEvent event;
657 int x;
659 while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
660 if ((x = evDispatch(opaqueCtx, event)) < 0)
661 break;
662 return (x);
666 evHighestFD(evContext opaqueCtx) {
667 evContext_p *ctx = opaqueCtx.opaque;
669 return (ctx->highestFD);
672 void
673 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
674 va_list ap;
676 va_start(ap, fmt);
677 if (ctx->output != NULL && ctx->debug >= level) {
678 vfprintf(ctx->output, fmt, ap);
679 fflush(ctx->output);
681 va_end(ap);
685 evSetOption(evContext *opaqueCtx, const char *option, int value) {
686 /* evContext_p *ctx = opaqueCtx->opaque; */
688 UNUSED(opaqueCtx);
689 UNUSED(value);
690 #ifndef CLOCK_MONOTONIC
691 UNUSED(option);
692 #endif
694 #ifdef CLOCK_MONOTONIC
695 if (strcmp(option, "monotime") == 0) {
696 if (opaqueCtx != NULL)
697 errno = EINVAL;
698 if (value == 0 || value == 1) {
699 __evOptMonoTime = value;
700 return (0);
701 } else {
702 errno = EINVAL;
703 return (-1);
706 #endif
707 errno = ENOENT;
708 return (-1);
712 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
713 /* evContext_p *ctx = opaqueCtx->opaque; */
715 UNUSED(opaqueCtx);
716 #ifndef CLOCK_MONOTONIC
717 UNUSED(value);
718 UNUSED(option);
719 #endif
721 #ifdef CLOCK_MONOTONIC
722 if (strcmp(option, "monotime") == 0) {
723 if (opaqueCtx != NULL)
724 errno = EINVAL;
725 *value = __evOptMonoTime;
726 return (0);
728 #endif
729 errno = ENOENT;
730 return (-1);
733 #if defined(NEED_PSELECT) || defined(USE_POLL)
734 /* XXX needs to move to the porting library. */
735 static int
736 pselect(int nfds, void *rfds, void *wfds, void *efds,
737 struct timespec *tsp,
738 const sigset_t *sigmask)
740 struct timeval tv, *tvp;
741 sigset_t sigs;
742 int n;
743 #ifdef USE_POLL
744 int polltimeout = INFTIM;
745 evContext_p *ctx;
746 struct pollfd *fds;
747 nfds_t pnfds;
749 UNUSED(nfds);
750 #endif /* USE_POLL */
752 if (tsp) {
753 tvp = &tv;
754 tv = evTimeVal(*tsp);
755 #ifdef USE_POLL
756 polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000;
757 #endif /* USE_POLL */
758 } else
759 tvp = NULL;
760 if (sigmask)
761 sigprocmask(SIG_SETMASK, sigmask, &sigs);
762 #ifndef USE_POLL
763 n = select(nfds, rfds, wfds, efds, tvp);
764 #else
766 * rfds, wfds, and efds should all be from the same evContext_p,
767 * so any of them will do. If they're all NULL, the caller is
768 * presumably calling us to block.
770 if (rfds != NULL)
771 ctx = ((__evEmulMask *)rfds)->ctx;
772 else if (wfds != NULL)
773 ctx = ((__evEmulMask *)wfds)->ctx;
774 else if (efds != NULL)
775 ctx = ((__evEmulMask *)efds)->ctx;
776 else
777 ctx = NULL;
778 if (ctx != NULL && ctx->fdMax != -1) {
779 fds = &(ctx->pollfds[ctx->firstfd]);
780 pnfds = ctx->fdMax - ctx->firstfd + 1;
781 } else {
782 fds = NULL;
783 pnfds = 0;
785 n = poll(fds, pnfds, polltimeout);
786 if (n > 0) {
787 int i, e;
789 INSIST(ctx != NULL);
790 for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
791 if (ctx->pollfds[i].fd < 0)
792 continue;
793 if (FD_ISSET(i, &ctx->rdLast))
794 e++;
795 if (FD_ISSET(i, &ctx->wrLast))
796 e++;
797 if (FD_ISSET(i, &ctx->exLast))
798 e++;
800 n = e;
802 #endif /* USE_POLL */
803 if (sigmask)
804 sigprocmask(SIG_SETMASK, &sigs, NULL);
805 if (tsp)
806 *tsp = evTimeSpec(tv);
807 return (n);
809 #endif
811 #ifdef USE_POLL
813 evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
815 int i, maxnfds;
816 void *pollfds, *fdTable;
818 if (fd < ctx->maxnfds)
819 return (0);
821 /* Don't allow ridiculously small values for pollfd_chunk_size */
822 if (pollfd_chunk_size < 20)
823 pollfd_chunk_size = 20;
825 maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
827 pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds));
828 if (pollfds != NULL)
829 ctx->pollfds = pollfds;
830 fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable));
831 if (fdTable != NULL)
832 ctx->fdTable = fdTable;
834 if (pollfds == NULL || fdTable == NULL) {
835 evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
836 (long)maxnfds*sizeof(struct pollfd));
837 return (-1);
840 for (i = ctx->maxnfds; i < maxnfds; i++) {
841 ctx->pollfds[i].fd = -1;
842 ctx->pollfds[i].events = 0;
843 ctx->fdTable[i] = 0;
846 ctx->maxnfds = maxnfds;
848 return (0);
851 /* Find the appropriate 'events' or 'revents' field in the pollfds array */
852 short *
853 __fd_eventfield(int fd, __evEmulMask *maskp) {
855 evContext_p *ctx = (evContext_p *)maskp->ctx;
857 if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
858 return (&(ctx->pollfds[fd].events));
859 else
860 return (&(ctx->pollfds[fd].revents));
863 /* Translate to poll(2) event */
864 short
865 __poll_event(__evEmulMask *maskp) {
867 switch ((maskp)->type) {
868 case EV_READ:
869 return (POLLRDNORM);
870 case EV_WRITE:
871 return (POLLWRNORM);
872 case EV_EXCEPT:
873 return (POLLRDBAND | POLLPRI | POLLWRBAND);
874 case EV_WASNONBLOCKING:
875 return (POLLHUP);
876 default:
877 return (0);
882 * Clear the events corresponding to the specified mask. If this leaves
883 * the events mask empty (apart from the POLLHUP bit), set the fd field
884 * to -1 so that poll(2) will ignore this fd.
886 void
887 __fd_clr(int fd, __evEmulMask *maskp) {
889 evContext_p *ctx = maskp->ctx;
891 *__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
892 if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
893 ctx->pollfds[fd].fd = -1;
894 if (fd == ctx->fdMax)
895 while (ctx->fdMax > ctx->firstfd &&
896 ctx->pollfds[ctx->fdMax].fd < 0)
897 ctx->fdMax--;
898 if (fd == ctx->firstfd)
899 while (ctx->firstfd <= ctx->fdMax &&
900 ctx->pollfds[ctx->firstfd].fd < 0)
901 ctx->firstfd++;
903 * Do we have a empty set of descriptors?
905 if (ctx->firstfd > ctx->fdMax) {
906 ctx->fdMax = -1;
907 ctx->firstfd = 0;
913 * Set the events bit(s) corresponding to the specified mask. If the events
914 * field has any other bits than POLLHUP set, also set the fd field so that
915 * poll(2) will watch this fd.
917 void
918 __fd_set(int fd, __evEmulMask *maskp) {
920 evContext_p *ctx = maskp->ctx;
922 *__fd_eventfield(fd, maskp) |= __poll_event(maskp);
923 if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
924 ctx->pollfds[fd].fd = fd;
925 if (fd < ctx->firstfd || ctx->fdMax == -1)
926 ctx->firstfd = fd;
927 if (fd > ctx->fdMax)
928 ctx->fdMax = fd;
931 #endif /* USE_POLL */
933 /*! \file */