Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / bind / isc / eventlib.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1995-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 /* eventlib.c - implement glue for the eventlib
19  * vix 09sep95 [initial]
20  */
21
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
25
26 #include "port_before.h"
27 #include "fd_setsize.h"
28
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 */
35
36 #include <errno.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41
42 #include <isc/eventlib.h>
43 #include <isc/assertions.h>
44 #include "eventlib_p.h"
45
46 #include "port_after.h"
47
48 int      __evOptMonoTime;
49
50 #ifdef USE_POLL
51 #define pselect Pselect
52 #endif /* USE_POLL */
53
54 /* Forward. */
55
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
61
62 int    __evOptMonoTime;
63
64 /* Public. */
65
66 int
67 evCreate(evContext *opaqueCtx) {
68         evContext_p *ctx;
69
70         /* Make sure the memory heap is initialized. */
71         if (meminit(0, 0) < 0 && errno != EEXIST)
72                 return (-1);
73
74         OKNEW(ctx);
75
76         /* Global. */
77         ctx->cur = NULL;
78
79         /* Debugging. */
80         ctx->debug = 0;
81         ctx->output = NULL;
82
83         /* Connections. */
84         ctx->conns = NULL;
85         INIT_LIST(ctx->accepts);
86
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
118
119         /* Streams. */
120         ctx->streams = NULL;
121         ctx->strDone = NULL;
122         ctx->strLast = NULL;
123
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);
132
133         /* Waits. */
134         ctx->waitLists = NULL;
135         ctx->waitDone.first = ctx->waitDone.last = NULL;
136         ctx->waitDone.prev = ctx->waitDone.next = NULL;
137
138         opaqueCtx->opaque = ctx;
139         return (0);
140 }
141
142 void
143 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
144         evContext_p *ctx = opaqueCtx.opaque;
145
146         ctx->debug = level;
147         ctx->output = output;
148 }
149
150 int
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;
156
157         /* Connections. */
158         while (revs-- > 0 && ctx->conns != NULL) {
159                 evConnID id;
160
161                 id.opaque = ctx->conns;
162                 (void) evCancelConn(opaqueCtx, id);
163         }
164         INSIST(revs >= 0);
165
166         /* Streams. */
167         while (revs-- > 0 && ctx->streams != NULL) {
168                 evStreamID id;
169
170                 id.opaque = ctx->streams;
171                 (void) evCancelRW(opaqueCtx, id);
172         }
173
174         /* Files. */
175         while (revs-- > 0 && ctx->files != NULL) {
176                 evFileID id;
177
178                 id.opaque = ctx->files;
179                 (void) evDeselectFD(opaqueCtx, id);
180         }
181         INSIST(revs >= 0);
182
183         /* Timers. */
184         evDestroyTimers(ctx);
185
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);
196                 }
197                 FREE(this_wl);
198         }
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);
204         }
205
206         FREE(ctx);
207         return (0);
208 }
209
210 int
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
220
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);
225
226         /* Get the time of day.  We'll do this again after select() blocks. */
227         ctx->lastEventTime = evNowTime();
228
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);
238         }
239
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);
250         }
251
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);
262         }
263
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;
275
276                 /* Are there any events at all? */
277                 if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
278                         EV_ERR(ENOENT);
279
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;
297                 }
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);
307                 }
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
316                         /*
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.
321                          */
322 #endif /* USE_POLL */
323                         if (m == Timer) {
324                                 INSIST(tp == &t);
325                                 t = evSubTime(nextTime, ctx->lastEventTime);
326                         }
327
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;
333
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();
344
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);
360                         }
361                         if (pselect_errno == EBADF) {
362                                 for (x = 0; x <= ctx->fdMax; x++) {
363                                         struct stat sb;
364
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",
372                                                          x);
373                                 }
374                                 abort();
375                         }
376                         EV_ERR(pselect_errno);
377                 }
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
385         }
386         INSIST(nextTimer || ctx->fdCount);
387
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);
392         }
393         if (nextTimer && timerPast) {
394                 OKNEW(new);
395                 new->type = Timer;
396                 new->u.timer.this = nextTimer;
397                 opaqueEv->opaque = new;
398                 return (0);
399         }
400
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;
406
407                 if (ctx->fdNext == NULL) {
408                         if (++x == 2) {
409                                 /*
410                                  * Hitting the end twice means that the last
411                                  * select() found some FD's which have since
412                                  * been deselected.
413                                  *
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().
424                                  */
425                                 ctx->fdCount = 0;
426                                 break;
427                         }
428                         ctx->fdNext = ctx->files;
429                 }
430                 fid = ctx->fdNext;
431                 ctx->fdNext = fid->next;
432
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--;
446                         }
447                         if ((eventmask & EV_WRITE) != 0) {
448                                 FD_CLR(fd, &ctx->wrLast);
449                                 ctx->fdCount--;
450                         }
451                         if ((eventmask & EV_EXCEPT) != 0) {
452                                 FD_CLR(fd, &ctx->exLast);
453                                 ctx->fdCount--;
454                         }
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);
461                 }
462         }
463         if (ctx->fdCount < 0) {
464                 /*
465                  * select()'s count is off on a number of systems, and
466                  * can result in fdCount < 0.
467                  */
468                 evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
469                 ctx->fdCount = 0;
470         }
471
472         /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
473         goto again;
474 }
475
476 int
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
485
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;
494
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;
507             }
508             case File: {
509                 evFile *this = ev->u.file.this;
510                 int eventmask = ev->u.file.eventmask;
511
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;
520             }
521             case Stream: {
522                 evStream *this = ev->u.stream.this;
523
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;
533             }
534             case Timer: {
535                 evTimer *this = ev->u.timer.this;
536
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;
544             }
545             case Wait: {
546                 evWait *this = ev->u.wait.this;
547
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;
556             }
557             case Null: {
558                 /* No work. */
559 #ifdef EVENTLIB_TIME_CHECKS
560                 func = NULL;
561 #endif
562                 break;
563             }
564             default: {
565                 abort();
566             }
567         }
568 #ifdef EVENTLIB_TIME_CHECKS
569         if (ctx->debug > 0) {
570                 interval = evSubTime(evNowTime(), start_time);
571                 /* 
572                  * Complain if it took longer than 50 milliseconds.
573                  *
574                  * We call getuid() to make an easy to find mark in a kernel
575                  * trace.
576                  */
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);
582         }
583 #endif
584         ctx->cur = NULL;
585         evDrop(opaqueCtx, opaqueEv);
586         return (0);
587 }
588
589 void
590 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
591         evContext_p *ctx = opaqueCtx.opaque;
592         evEvent_p *ev = opaqueEv.opaque;
593
594         switch (ev->type) {
595             case Accept: {
596                 FREE(ev->u.accept.this);
597                 break;
598             }
599             case File: {
600                 /* No work. */
601                 break;
602             }
603             case Stream: {
604                 evStreamID id;
605
606                 id.opaque = ev->u.stream.this;
607                 (void) evCancelRW(opaqueCtx, id);
608                 break;
609             }
610             case Timer: {
611                 evTimer *this = ev->u.timer.this;
612                 evTimerID opaque;
613
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;
618                 }
619                 /*
620                  * Timer is still there.  Delete it if it has expired,
621                  * otherwise set it according to its next interval.
622                  */
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);
636                 }
637                 break;
638             }
639             case Wait: {
640                 FREE(ev->u.wait.this);
641                 break;
642             }
643             case Null: {
644                 /* No work. */
645                 break;
646             }
647             default: {
648                 abort();
649             }
650         }
651         FREE(ev);
652 }
653
654 int
655 evMainLoop(evContext opaqueCtx) {
656         evEvent event;
657         int x;
658
659         while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
660                 if ((x = evDispatch(opaqueCtx, event)) < 0)
661                         break;
662         return (x);
663 }
664
665 int
666 evHighestFD(evContext opaqueCtx) {
667         evContext_p *ctx = opaqueCtx.opaque;
668
669         return (ctx->highestFD);
670 }
671
672 void
673 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
674         va_list ap;
675
676         va_start(ap, fmt);
677         if (ctx->output != NULL && ctx->debug >= level) {
678                 vfprintf(ctx->output, fmt, ap);
679                 fflush(ctx->output);
680         }
681         va_end(ap);
682 }
683
684 int
685 evSetOption(evContext *opaqueCtx, const char *option, int value) {
686         /* evContext_p *ctx = opaqueCtx->opaque; */
687
688         UNUSED(opaqueCtx);
689         UNUSED(value);
690 #ifndef CLOCK_MONOTONIC
691         UNUSED(option);
692 #endif 
693
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);
704                 }
705         } 
706 #endif
707         errno = ENOENT;
708         return (-1);
709 }
710
711 int
712 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
713         /* evContext_p *ctx = opaqueCtx->opaque; */
714
715         UNUSED(opaqueCtx);
716 #ifndef CLOCK_MONOTONIC
717         UNUSED(value);
718         UNUSED(option);
719 #endif 
720
721 #ifdef CLOCK_MONOTONIC
722         if (strcmp(option, "monotime") == 0) {
723                 if (opaqueCtx  != NULL)
724                         errno = EINVAL;
725                 *value = __evOptMonoTime;
726                 return (0);
727         }
728 #endif
729         errno = ENOENT;
730         return (-1);
731 }
732
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)
739 {
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;
748
749         UNUSED(nfds);
750 #endif /* USE_POLL */
751
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
765         /*
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.
769          */
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;
784         }
785         n = poll(fds, pnfds, polltimeout);
786         if (n > 0) {
787                 int     i, e;
788
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++;
799                 }
800                 n = e;
801         }
802 #endif /* USE_POLL */
803         if (sigmask)
804                 sigprocmask(SIG_SETMASK, &sigs, NULL);
805         if (tsp)
806                 *tsp = evTimeSpec(tv);
807         return (n);
808 }
809 #endif
810
811 #ifdef USE_POLL
812 int
813 evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
814  
815         int     i, maxnfds;
816         void    *pollfds, *fdTable;
817  
818         if (fd < ctx->maxnfds)
819                 return (0);
820  
821         /* Don't allow ridiculously small values for pollfd_chunk_size */
822         if (pollfd_chunk_size < 20)
823                 pollfd_chunk_size = 20;
824  
825         maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
826  
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;
833  
834         if (pollfds == NULL || fdTable == NULL) {
835                 evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
836                          (long)maxnfds*sizeof(struct pollfd));
837                 return (-1);
838         }
839  
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;
844         }
845
846         ctx->maxnfds = maxnfds;
847
848         return (0);
849 }
850  
851 /* Find the appropriate 'events' or 'revents' field in the pollfds array */
852 short *
853 __fd_eventfield(int fd, __evEmulMask *maskp) {
854  
855         evContext_p     *ctx = (evContext_p *)maskp->ctx;
856  
857         if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
858                 return (&(ctx->pollfds[fd].events));
859         else
860                 return (&(ctx->pollfds[fd].revents));
861 }
862  
863 /* Translate to poll(2) event */
864 short
865 __poll_event(__evEmulMask *maskp) {
866  
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);
878         }
879 }
880  
881 /*
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.
885  */
886 void
887 __fd_clr(int fd, __evEmulMask *maskp) {
888  
889         evContext_p     *ctx = maskp->ctx;
890  
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++;
902                 /*
903                  * Do we have a empty set of descriptors?
904                  */
905                 if (ctx->firstfd > ctx->fdMax) {
906                         ctx->fdMax = -1;
907                         ctx->firstfd = 0;
908                 }
909         }
910 }
911  
912 /*
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.
916  */
917 void
918 __fd_set(int fd, __evEmulMask *maskp) {
919  
920         evContext_p     *ctx = maskp->ctx;
921
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;
929         }
930 }
931 #endif /* USE_POLL */
932
933 /*! \file */