]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/bind/isc/eventlib.c
This commit was generated by cvs2svn to compensate for changes in r151937,
[FreeBSD/FreeBSD.git] / contrib / bind9 / 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.2.2.1.4.4 2004/12/09 04:07:15 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
33 #include <errno.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38
39 #include <isc/eventlib.h>
40 #include <isc/assertions.h>
41 #include "eventlib_p.h"
42
43 #include "port_after.h"
44
45 int      __evOptMonoTime;
46
47 /* Forward. */
48
49 #ifdef NEED_PSELECT
50 static int              pselect(int, void *, void *, void *,
51                                 struct timespec *,
52                                 const sigset_t *);
53 #endif
54
55 int    __evOptMonoTime;
56
57 /* Public. */
58
59 int
60 evCreate(evContext *opaqueCtx) {
61         evContext_p *ctx;
62
63         /* Make sure the memory heap is initialized. */
64         if (meminit(0, 0) < 0 && errno != EEXIST)
65                 return (-1);
66
67         OKNEW(ctx);
68
69         /* Global. */
70         ctx->cur = NULL;
71
72         /* Debugging. */
73         ctx->debug = 0;
74         ctx->output = NULL;
75
76         /* Connections. */
77         ctx->conns = NULL;
78         INIT_LIST(ctx->accepts);
79
80         /* Files. */
81         ctx->files = NULL;
82         FD_ZERO(&ctx->rdNext);
83         FD_ZERO(&ctx->wrNext);
84         FD_ZERO(&ctx->exNext);
85         FD_ZERO(&ctx->nonblockBefore);
86         ctx->fdMax = -1;
87         ctx->fdNext = NULL;
88         ctx->fdCount = 0;       /* Invalidate {rd,wr,ex}Last. */
89         ctx->highestFD = FD_SETSIZE - 1;
90 #ifdef EVENTLIB_TIME_CHECKS
91         ctx->lastFdCount = 0;
92 #endif
93         memset(ctx->fdTable, 0, sizeof ctx->fdTable);
94
95         /* Streams. */
96         ctx->streams = NULL;
97         ctx->strDone = NULL;
98         ctx->strLast = NULL;
99
100         /* Timers. */
101         ctx->lastEventTime = evNowTime();
102 #ifdef EVENTLIB_TIME_CHECKS
103         ctx->lastSelectTime = ctx->lastEventTime;
104 #endif
105         ctx->timers = evCreateTimers(ctx);
106         if (ctx->timers == NULL)
107                 return (-1);
108
109         /* Waits. */
110         ctx->waitLists = NULL;
111         ctx->waitDone.first = ctx->waitDone.last = NULL;
112         ctx->waitDone.prev = ctx->waitDone.next = NULL;
113
114         opaqueCtx->opaque = ctx;
115         return (0);
116 }
117
118 void
119 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
120         evContext_p *ctx = opaqueCtx.opaque;
121
122         ctx->debug = level;
123         ctx->output = output;
124 }
125
126 int
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;
132
133         /* Connections. */
134         while (revs-- > 0 && ctx->conns != NULL) {
135                 evConnID id;
136
137                 id.opaque = ctx->conns;
138                 (void) evCancelConn(opaqueCtx, id);
139         }
140         INSIST(revs >= 0);
141
142         /* Streams. */
143         while (revs-- > 0 && ctx->streams != NULL) {
144                 evStreamID id;
145
146                 id.opaque = ctx->streams;
147                 (void) evCancelRW(opaqueCtx, id);
148         }
149
150         /* Files. */
151         while (revs-- > 0 && ctx->files != NULL) {
152                 evFileID id;
153
154                 id.opaque = ctx->files;
155                 (void) evDeselectFD(opaqueCtx, id);
156         }
157         INSIST(revs >= 0);
158
159         /* Timers. */
160         evDestroyTimers(ctx);
161
162         /* Waits. */
163         for (this_wl = ctx->waitLists;
164              revs-- > 0 && this_wl != NULL;
165              this_wl = next_wl) {
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;
171                         FREE(this_wait);
172                 }
173                 FREE(this_wl);
174         }
175         for (this_wait = ctx->waitDone.first;
176              revs-- > 0 && this_wait != NULL;
177              this_wait = next_wait) {
178                 next_wait = this_wait->next;
179                 FREE(this_wait);
180         }
181
182         FREE(ctx);
183         return (0);
184 }
185
186 int
187 evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
188         evContext_p *ctx = opaqueCtx.opaque;
189         struct timespec nextTime;
190         evTimer *nextTimer;
191         evEvent_p *new;
192         int x, pselect_errno, timerPast;
193 #ifdef EVENTLIB_TIME_CHECKS
194         struct timespec interval;
195 #endif
196
197         /* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
198         x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
199         if (x != 1)
200                 EV_ERR(EINVAL);
201
202         /* Get the time of day.  We'll do this again after select() blocks. */
203         ctx->lastEventTime = evNowTime();
204
205  again:
206         /* Finished accept()'s do not require a select(). */
207         if (!EMPTY(ctx->accepts)) {
208                 OKNEW(new);
209                 new->type = Accept;
210                 new->u.accept.this = HEAD(ctx->accepts);
211                 UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
212                 opaqueEv->opaque = new;
213                 return (0);
214         }
215
216         /* Stream IO does not require a select(). */
217         if (ctx->strDone != NULL) {
218                 OKNEW(new);
219                 new->type = Stream;
220                 new->u.stream.this = ctx->strDone;
221                 ctx->strDone = ctx->strDone->nextDone;
222                 if (ctx->strDone == NULL)
223                         ctx->strLast = NULL;
224                 opaqueEv->opaque = new;
225                 return (0);
226         }
227
228         /* Waits do not require a select(). */
229         if (ctx->waitDone.first != NULL) {
230                 OKNEW(new);
231                 new->type = Wait;
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;
237                 return (0);
238         }
239
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);
244         } else
245                 timerPast = 0;  /* Make gcc happy. */
246
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;
252
253                 /* Are there any events at all? */
254                 if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
255                         EV_ERR(ENOENT);
256
257                 /* Figure out what select()'s timeout parameter should be. */
258                 if ((options & EV_POLL) != 0) {
259                         m = JustPoll;
260                         t = NoTime;
261                         tp = &t;
262                 } else if (nextTimer == NULL) {
263                         m = Block;
264                         /* ``t'' unused. */
265                         tp = NULL;
266                 } else if (timerPast) {
267                         m = JustPoll;
268                         t = NoTime;
269                         tp = &t;
270                 } else {
271                         m = Timer;
272                         /* ``t'' filled in later. */
273                         tp = &t;
274                 }
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)
280                                 evPrintf(ctx, 1,
281                                    "time between pselect() %u.%09u count %d\n",
282                                          interval.tv_sec, interval.tv_nsec,
283                                          ctx->lastFdCount);
284                 }
285 #endif
286                 do {
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;
291
292                         if (m == Timer) {
293                                 INSIST(tp == &t);
294                                 t = evSubTime(nextTime, ctx->lastEventTime);
295                         }
296
297                         evPrintf(ctx, 4,
298                                 "pselect(%d, 0x%lx, 0x%lx, 0x%lx, %ld.%09ld)\n",
299                                  ctx->fdMax+1,
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);
305
306                         /* XXX should predict system's earliness and adjust. */
307                         x = pselect(ctx->fdMax+1,
308                                     &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
309                                     tp, NULL);
310                         pselect_errno = errno;
311
312                         evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
313                                  x, (x == -1) ? strerror(errno) : "none");
314
315                         /* Anything but a poll can change the time. */
316                         if (m != JustPoll)
317                                 ctx->lastEventTime = evNowTime();
318
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;
324 #endif
325                 if (x < 0) {
326                         if (pselect_errno == EINTR) {
327                                 if ((options & EV_NULL) != 0)
328                                         goto again;
329                                 OKNEW(new);
330                                 new->type = Null;
331                                 /* No data. */
332                                 opaqueEv->opaque = new;
333                                 return (0);
334                         }
335                         if (pselect_errno == EBADF) {
336                                 for (x = 0; x <= ctx->fdMax; x++) {
337                                         struct stat sb;
338
339                                         if (FD_ISSET(x, &ctx->rdNext) == 0 &&
340                                             FD_ISSET(x, &ctx->wrNext) == 0 &&
341                                             FD_ISSET(x, &ctx->exNext) == 0)
342                                                 continue;
343                                         if (fstat(x, &sb) == -1 &&
344                                             errno == EBADF)
345                                                 evPrintf(ctx, 1, "EBADF: %d\n",
346                                                          x);
347                                 }
348                                 abort();
349                         }
350                         EV_ERR(pselect_errno);
351                 }
352                 if (x == 0 && (nextTimer == NULL || !timerPast) &&
353                     (options & EV_POLL))
354                         EV_ERR(EWOULDBLOCK);
355                 ctx->fdCount = x;
356 #ifdef EVENTLIB_TIME_CHECKS
357                 ctx->lastFdCount = x;
358 #endif
359         }
360         INSIST(nextTimer || ctx->fdCount);
361
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);
366         }
367         if (nextTimer && timerPast) {
368                 OKNEW(new);
369                 new->type = Timer;
370                 new->u.timer.this = nextTimer;
371                 opaqueEv->opaque = new;
372                 return (0);
373         }
374
375         /* No timers, so there should be a ready file descriptor. */
376         x = 0;
377         while (ctx->fdCount > 0) {
378                 evFile *fid;
379                 int fd, eventmask;
380
381                 if (ctx->fdNext == NULL) {
382                         if (++x == 2) {
383                                 /*
384                                  * Hitting the end twice means that the last
385                                  * select() found some FD's which have since
386                                  * been deselected.
387                                  *
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
397                                  * extra select().
398                                  */
399                                 ctx->fdCount = 0;
400                                 break;
401                         }
402                         ctx->fdNext = ctx->files;
403                 }
404                 fid = ctx->fdNext;
405                 ctx->fdNext = fid->next;
406
407                 fd = fid->fd;
408                 eventmask = 0;
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);
419                                 ctx->fdCount--;
420                         }
421                         if ((eventmask & EV_WRITE) != 0) {
422                                 FD_CLR(fd, &ctx->wrLast);
423                                 ctx->fdCount--;
424                         }
425                         if ((eventmask & EV_EXCEPT) != 0) {
426                                 FD_CLR(fd, &ctx->exLast);
427                                 ctx->fdCount--;
428                         }
429                         OKNEW(new);
430                         new->type = File;
431                         new->u.file.this = fid;
432                         new->u.file.eventmask = eventmask;
433                         opaqueEv->opaque = new;
434                         return (0);
435                 }
436         }
437         if (ctx->fdCount < 0) {
438                 /*
439                  * select()'s count is off on a number of systems, and
440                  * can result in fdCount < 0.
441                  */
442                 evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
443                 ctx->fdCount = 0;
444         }
445
446         /* We get here if the caller deselect()'s an FD. Gag me with a goto. */
447         goto again;
448 }
449
450 int
451 evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
452         evContext_p *ctx = opaqueCtx.opaque;
453         evEvent_p *ev = opaqueEv.opaque;
454 #ifdef EVENTLIB_TIME_CHECKS
455         void *func;
456         struct timespec start_time;
457         struct timespec interval;
458 #endif
459
460 #ifdef EVENTLIB_TIME_CHECKS
461         if (ctx->debug > 0)
462                 start_time = evNowTime();
463 #endif
464         ctx->cur = ev;
465         switch (ev->type) {
466             case Accept: {
467                 evAccept *this = ev->u.accept.this;
468
469                 evPrintf(ctx, 5,
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;
479 #endif
480                 break;
481             }
482             case File: {
483                 evFile *this = ev->u.file.this;
484                 int eventmask = ev->u.file.eventmask;
485
486                 evPrintf(ctx, 5,
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
491                 func = this->func;
492 #endif
493                 break;
494             }
495             case Stream: {
496                 evStream *this = ev->u.stream.this;
497
498                 evPrintf(ctx, 5,
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
504                 func = this->func;
505 #endif
506                 break;
507             }
508             case Timer: {
509                 evTimer *this = ev->u.timer.this;
510
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
515                 func = this->func;
516 #endif
517                 break;
518             }
519             case Wait: {
520                 evWait *this = ev->u.wait.this;
521
522                 evPrintf(ctx, 5,
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
527                 func = this->func;
528 #endif
529                 break;
530             }
531             case Null: {
532                 /* No work. */
533 #ifdef EVENTLIB_TIME_CHECKS
534                 func = NULL;
535 #endif
536                 break;
537             }
538             default: {
539                 abort();
540             }
541         }
542 #ifdef EVENTLIB_TIME_CHECKS
543         if (ctx->debug > 0) {
544                 interval = evSubTime(evNowTime(), start_time);
545                 /* 
546                  * Complain if it took longer than 50 milliseconds.
547                  *
548                  * We call getuid() to make an easy to find mark in a kernel
549                  * trace.
550                  */
551                 if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
552                         evPrintf(ctx, 1,
553                          "dispatch interval %u.%09u uid %d type %d func %p\n",
554                                  interval.tv_sec, interval.tv_nsec,
555                                  getuid(), ev->type, func);
556         }
557 #endif
558         ctx->cur = NULL;
559         evDrop(opaqueCtx, opaqueEv);
560         return (0);
561 }
562
563 void
564 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
565         evContext_p *ctx = opaqueCtx.opaque;
566         evEvent_p *ev = opaqueEv.opaque;
567
568         switch (ev->type) {
569             case Accept: {
570                 FREE(ev->u.accept.this);
571                 break;
572             }
573             case File: {
574                 /* No work. */
575                 break;
576             }
577             case Stream: {
578                 evStreamID id;
579
580                 id.opaque = ev->u.stream.this;
581                 (void) evCancelRW(opaqueCtx, id);
582                 break;
583             }
584             case Timer: {
585                 evTimer *this = ev->u.timer.this;
586                 evTimerID opaque;
587
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");
591                         break;
592                 }
593                 /*
594                  * Timer is still there.  Delete it if it has expired,
595                  * otherwise set it according to its next interval.
596                  */
597                 if (this->inter.tv_sec == (time_t)0 &&
598                     this->inter.tv_nsec == 0L) {
599                         opaque.opaque = this;                   
600                         (void) evClearTimer(opaqueCtx, opaque);
601                 } else {
602                         opaque.opaque = this;
603                         (void) evResetTimer(opaqueCtx, opaque, this->func,
604                                             this->uap,
605                                             evAddTime((this->mode & EV_TMR_RATE) ?
606                                                       this->due :
607                                                       ctx->lastEventTime,
608                                                       this->inter),
609                                             this->inter);
610                 }
611                 break;
612             }
613             case Wait: {
614                 FREE(ev->u.wait.this);
615                 break;
616             }
617             case Null: {
618                 /* No work. */
619                 break;
620             }
621             default: {
622                 abort();
623             }
624         }
625         FREE(ev);
626 }
627
628 int
629 evMainLoop(evContext opaqueCtx) {
630         evEvent event;
631         int x;
632
633         while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
634                 if ((x = evDispatch(opaqueCtx, event)) < 0)
635                         break;
636         return (x);
637 }
638
639 int
640 evHighestFD(evContext opaqueCtx) {
641         evContext_p *ctx = opaqueCtx.opaque;
642
643         return (ctx->highestFD);
644 }
645
646 void
647 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
648         va_list ap;
649
650         va_start(ap, fmt);
651         if (ctx->output != NULL && ctx->debug >= level) {
652                 vfprintf(ctx->output, fmt, ap);
653                 fflush(ctx->output);
654         }
655         va_end(ap);
656 }
657
658 int
659 evSetOption(evContext *opaqueCtx, const char *option, int value) {
660         /* evContext_p *ctx = opaqueCtx->opaque; */
661
662         UNUSED(opaqueCtx);
663         UNUSED(value);
664 #ifndef CLOCK_MONOTONIC
665         UNUSED(option);
666 #endif 
667
668 #ifdef CLOCK_MONOTONIC
669         if (strcmp(option, "monotime") == 0) {
670                 if (opaqueCtx  != NULL)
671                         errno = EINVAL;
672                 if (value == 0 || value == 1) {
673                         __evOptMonoTime = value;
674                         return (0);
675                 } else {
676                         errno = EINVAL;
677                         return (-1);
678                 }
679         } 
680 #endif
681         errno = ENOENT;
682         return (-1);
683 }
684
685 int
686 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
687         /* evContext_p *ctx = opaqueCtx->opaque; */
688
689         UNUSED(opaqueCtx);
690 #ifndef CLOCK_MONOTONIC
691         UNUSED(value);
692         UNUSED(option);
693 #endif 
694
695 #ifdef CLOCK_MONOTONIC
696         if (strcmp(option, "monotime") == 0) {
697                 if (opaqueCtx  != NULL)
698                         errno = EINVAL;
699                 *value = __evOptMonoTime;
700                 return (0);
701         }
702 #endif
703         errno = ENOENT;
704         return (-1);
705 }
706
707 #ifdef NEED_PSELECT
708 /* XXX needs to move to the porting library. */
709 static int
710 pselect(int nfds, void *rfds, void *wfds, void *efds,
711         struct timespec *tsp,
712         const sigset_t *sigmask)
713 {
714         struct timeval tv, *tvp;
715         sigset_t sigs;
716         int n;
717
718         if (tsp) {
719                 tvp = &tv;
720                 tv = evTimeVal(*tsp);
721         } else
722                 tvp = NULL;
723         if (sigmask)
724                 sigprocmask(SIG_SETMASK, sigmask, &sigs);
725         n = select(nfds, rfds, wfds, efds, tvp);
726         if (sigmask)
727                 sigprocmask(SIG_SETMASK, &sigs, NULL);
728         if (tsp)
729                 *tsp = evTimeSpec(tv);
730         return (n);
731 }
732 #endif