Home | History | Annotate | Line # | Download | only in isc
eventlib.c revision 1.1.1.1
      1 /*	$NetBSD: eventlib.c,v 1.1.1.1 2009/04/12 15:33:46 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
      5  * Copyright (c) 1995-1999 by Internet Software Consortium
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 /* eventlib.c - implement glue for the eventlib
     21  * vix 09sep95 [initial]
     22  */
     23 
     24 #if !defined(LINT) && !defined(CODECENTER)
     25 static const char rcsid[] = "Id: eventlib.c,v 1.10 2006/03/09 23:57:56 marka Exp";
     26 #endif
     27 
     28 #include "port_before.h"
     29 #include "fd_setsize.h"
     30 
     31 #include <sys/types.h>
     32 #include <sys/time.h>
     33 #include <sys/stat.h>
     34 #ifdef	SOLARIS2
     35 #include <limits.h>
     36 #endif	/* SOLARIS2 */
     37 
     38 #include <errno.h>
     39 #include <signal.h>
     40 #include <stdarg.h>
     41 #include <stdlib.h>
     42 #include <unistd.h>
     43 
     44 #include <isc/eventlib.h>
     45 #include <isc/assertions.h>
     46 #include "eventlib_p.h"
     47 
     48 #include "port_after.h"
     49 
     50 int      __evOptMonoTime;
     51 
     52 #ifdef USE_POLL
     53 #define	pselect Pselect
     54 #endif /* USE_POLL */
     55 
     56 /* Forward. */
     57 
     58 #if defined(NEED_PSELECT) || defined(USE_POLL)
     59 static int		pselect(int, void *, void *, void *,
     60 				struct timespec *,
     61 				const sigset_t *);
     62 #endif
     63 
     64 int    __evOptMonoTime;
     65 
     66 /* Public. */
     67 
     68 int
     69 evCreate(evContext *opaqueCtx) {
     70 	evContext_p *ctx;
     71 
     72 	/* Make sure the memory heap is initialized. */
     73 	if (meminit(0, 0) < 0 && errno != EEXIST)
     74 		return (-1);
     75 
     76 	OKNEW(ctx);
     77 
     78 	/* Global. */
     79 	ctx->cur = NULL;
     80 
     81 	/* Debugging. */
     82 	ctx->debug = 0;
     83 	ctx->output = NULL;
     84 
     85 	/* Connections. */
     86 	ctx->conns = NULL;
     87 	INIT_LIST(ctx->accepts);
     88 
     89 	/* Files. */
     90 	ctx->files = NULL;
     91 #ifdef USE_POLL
     92         ctx->pollfds = NULL;
     93 	ctx->maxnfds = 0;
     94 	ctx->firstfd = 0;
     95 	emulMaskInit(ctx, rdLast, EV_READ, 1);
     96 	emulMaskInit(ctx, rdNext, EV_READ, 0);
     97 	emulMaskInit(ctx, wrLast, EV_WRITE, 1);
     98 	emulMaskInit(ctx, wrNext, EV_WRITE, 0);
     99 	emulMaskInit(ctx, exLast, EV_EXCEPT, 1);
    100 	emulMaskInit(ctx, exNext, EV_EXCEPT, 0);
    101 	emulMaskInit(ctx, nonblockBefore, EV_WASNONBLOCKING, 0);
    102 #endif /* USE_POLL */
    103 	FD_ZERO(&ctx->rdNext);
    104 	FD_ZERO(&ctx->wrNext);
    105 	FD_ZERO(&ctx->exNext);
    106 	FD_ZERO(&ctx->nonblockBefore);
    107 	ctx->fdMax = -1;
    108 	ctx->fdNext = NULL;
    109 	ctx->fdCount = 0;	/*%< Invalidate {rd,wr,ex}Last. */
    110 #ifndef USE_POLL
    111 	ctx->highestFD = FD_SETSIZE - 1;
    112 	memset(ctx->fdTable, 0, sizeof ctx->fdTable);
    113 #else
    114 	ctx->highestFD = INT_MAX / sizeof(struct pollfd);
    115 	ctx->fdTable = NULL;
    116 #endif /* USE_POLL */
    117 #ifdef EVENTLIB_TIME_CHECKS
    118 	ctx->lastFdCount = 0;
    119 #endif
    120 
    121 	/* Streams. */
    122 	ctx->streams = NULL;
    123 	ctx->strDone = NULL;
    124 	ctx->strLast = NULL;
    125 
    126 	/* Timers. */
    127 	ctx->lastEventTime = evNowTime();
    128 #ifdef EVENTLIB_TIME_CHECKS
    129 	ctx->lastSelectTime = ctx->lastEventTime;
    130 #endif
    131 	ctx->timers = evCreateTimers(ctx);
    132 	if (ctx->timers == NULL)
    133 		return (-1);
    134 
    135 	/* Waits. */
    136 	ctx->waitLists = NULL;
    137 	ctx->waitDone.first = ctx->waitDone.last = NULL;
    138 	ctx->waitDone.prev = ctx->waitDone.next = NULL;
    139 
    140 	opaqueCtx->opaque = ctx;
    141 	return (0);
    142 }
    143 
    144 void
    145 evSetDebug(evContext opaqueCtx, int level, FILE *output) {
    146 	evContext_p *ctx = opaqueCtx.opaque;
    147 
    148 	ctx->debug = level;
    149 	ctx->output = output;
    150 }
    151 
    152 int
    153 evDestroy(evContext opaqueCtx) {
    154 	evContext_p *ctx = opaqueCtx.opaque;
    155 	int revs = 424242;	/*%< Doug Adams. */
    156 	evWaitList *this_wl, *next_wl;
    157 	evWait *this_wait, *next_wait;
    158 
    159 	/* Connections. */
    160 	while (revs-- > 0 && ctx->conns != NULL) {
    161 		evConnID id;
    162 
    163 		id.opaque = ctx->conns;
    164 		(void) evCancelConn(opaqueCtx, id);
    165 	}
    166 	INSIST(revs >= 0);
    167 
    168 	/* Streams. */
    169 	while (revs-- > 0 && ctx->streams != NULL) {
    170 		evStreamID id;
    171 
    172 		id.opaque = ctx->streams;
    173 		(void) evCancelRW(opaqueCtx, id);
    174 	}
    175 
    176 	/* Files. */
    177 	while (revs-- > 0 && ctx->files != NULL) {
    178 		evFileID id;
    179 
    180 		id.opaque = ctx->files;
    181 		(void) evDeselectFD(opaqueCtx, id);
    182 	}
    183 	INSIST(revs >= 0);
    184 
    185 	/* Timers. */
    186 	evDestroyTimers(ctx);
    187 
    188 	/* Waits. */
    189 	for (this_wl = ctx->waitLists;
    190 	     revs-- > 0 && this_wl != NULL;
    191 	     this_wl = next_wl) {
    192 		next_wl = this_wl->next;
    193 		for (this_wait = this_wl->first;
    194 		     revs-- > 0 && this_wait != NULL;
    195 		     this_wait = next_wait) {
    196 			next_wait = this_wait->next;
    197 			FREE(this_wait);
    198 		}
    199 		FREE(this_wl);
    200 	}
    201 	for (this_wait = ctx->waitDone.first;
    202 	     revs-- > 0 && this_wait != NULL;
    203 	     this_wait = next_wait) {
    204 		next_wait = this_wait->next;
    205 		FREE(this_wait);
    206 	}
    207 
    208 	FREE(ctx);
    209 	return (0);
    210 }
    211 
    212 int
    213 evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
    214 	evContext_p *ctx = opaqueCtx.opaque;
    215 	struct timespec nextTime;
    216 	evTimer *nextTimer;
    217 	evEvent_p *new;
    218 	int x, pselect_errno, timerPast;
    219 #ifdef EVENTLIB_TIME_CHECKS
    220 	struct timespec interval;
    221 #endif
    222 
    223 	/* Ensure that exactly one of EV_POLL or EV_WAIT was specified. */
    224 	x = ((options & EV_POLL) != 0) + ((options & EV_WAIT) != 0);
    225 	if (x != 1)
    226 		EV_ERR(EINVAL);
    227 
    228 	/* Get the time of day.  We'll do this again after select() blocks. */
    229 	ctx->lastEventTime = evNowTime();
    230 
    231  again:
    232 	/* Finished accept()'s do not require a select(). */
    233 	if (!EMPTY(ctx->accepts)) {
    234 		OKNEW(new);
    235 		new->type = Accept;
    236 		new->u.accept.this = HEAD(ctx->accepts);
    237 		UNLINK(ctx->accepts, HEAD(ctx->accepts), link);
    238 		opaqueEv->opaque = new;
    239 		return (0);
    240 	}
    241 
    242 	/* Stream IO does not require a select(). */
    243 	if (ctx->strDone != NULL) {
    244 		OKNEW(new);
    245 		new->type = Stream;
    246 		new->u.stream.this = ctx->strDone;
    247 		ctx->strDone = ctx->strDone->nextDone;
    248 		if (ctx->strDone == NULL)
    249 			ctx->strLast = NULL;
    250 		opaqueEv->opaque = new;
    251 		return (0);
    252 	}
    253 
    254 	/* Waits do not require a select(). */
    255 	if (ctx->waitDone.first != NULL) {
    256 		OKNEW(new);
    257 		new->type = Wait;
    258 		new->u.wait.this = ctx->waitDone.first;
    259 		ctx->waitDone.first = ctx->waitDone.first->next;
    260 		if (ctx->waitDone.first == NULL)
    261 			ctx->waitDone.last = NULL;
    262 		opaqueEv->opaque = new;
    263 		return (0);
    264 	}
    265 
    266 	/* Get the status and content of the next timer. */
    267 	if ((nextTimer = heap_element(ctx->timers, 1)) != NULL) {
    268 		nextTime = nextTimer->due;
    269 		timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
    270 	} else
    271 		timerPast = 0;	/*%< Make gcc happy. */
    272 	evPrintf(ctx, 9, "evGetNext: fdCount %d\n", ctx->fdCount);
    273 	if (ctx->fdCount == 0) {
    274 		static const struct timespec NoTime = {0, 0L};
    275 		enum { JustPoll, Block, Timer } m;
    276 		struct timespec t, *tp;
    277 
    278 		/* Are there any events at all? */
    279 		if ((options & EV_WAIT) != 0 && !nextTimer && ctx->fdMax == -1)
    280 			EV_ERR(ENOENT);
    281 
    282 		/* Figure out what select()'s timeout parameter should be. */
    283 		if ((options & EV_POLL) != 0) {
    284 			m = JustPoll;
    285 			t = NoTime;
    286 			tp = &t;
    287 		} else if (nextTimer == NULL) {
    288 			m = Block;
    289 			/* ``t'' unused. */
    290 			tp = NULL;
    291 		} else if (timerPast) {
    292 			m = JustPoll;
    293 			t = NoTime;
    294 			tp = &t;
    295 		} else {
    296 			m = Timer;
    297 			/* ``t'' filled in later. */
    298 			tp = &t;
    299 		}
    300 #ifdef EVENTLIB_TIME_CHECKS
    301 		if (ctx->debug > 0) {
    302 			interval = evSubTime(ctx->lastEventTime,
    303 					     ctx->lastSelectTime);
    304 			if (interval.tv_sec > 0 || interval.tv_nsec > 0)
    305 				evPrintf(ctx, 1,
    306 				   "time between pselect() %u.%09u count %d\n",
    307 					 interval.tv_sec, interval.tv_nsec,
    308 					 ctx->lastFdCount);
    309 		}
    310 #endif
    311 		do {
    312 #ifndef USE_POLL
    313 			 /* XXX need to copy only the bits we are using. */
    314 			 ctx->rdLast = ctx->rdNext;
    315 			 ctx->wrLast = ctx->wrNext;
    316 			 ctx->exLast = ctx->exNext;
    317 #else
    318 			/*
    319 			 * The pollfd structure uses separate fields for
    320 			 * the input and output events (corresponding to
    321 			 * the ??Next and ??Last fd sets), so there's no
    322 			 * need to copy one to the other.
    323 			 */
    324 #endif /* USE_POLL */
    325 			if (m == Timer) {
    326 				INSIST(tp == &t);
    327 				t = evSubTime(nextTime, ctx->lastEventTime);
    328 			}
    329 
    330 			/* XXX should predict system's earliness and adjust. */
    331 			x = pselect(ctx->fdMax+1,
    332 				    &ctx->rdLast, &ctx->wrLast, &ctx->exLast,
    333 				    tp, NULL);
    334 			pselect_errno = errno;
    335 
    336 #ifndef USE_POLL
    337 			evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
    338 				 x, (x == -1) ? strerror(errno) : "none");
    339 #else
    340 			evPrintf(ctx, 4, "poll() returns %d (err: %s)\n",
    341 				x, (x == -1) ? strerror(errno) : "none");
    342 #endif /* USE_POLL */
    343 			/* Anything but a poll can change the time. */
    344 			if (m != JustPoll)
    345 				ctx->lastEventTime = evNowTime();
    346 
    347 			/* Select() likes to finish about 10ms early. */
    348 		} while (x == 0 && m == Timer &&
    349 			 evCmpTime(ctx->lastEventTime, nextTime) < 0);
    350 #ifdef EVENTLIB_TIME_CHECKS
    351 		ctx->lastSelectTime = ctx->lastEventTime;
    352 #endif
    353 		if (x < 0) {
    354 			if (pselect_errno == EINTR) {
    355 				if ((options & EV_NULL) != 0)
    356 					goto again;
    357 				OKNEW(new);
    358 				new->type = Null;
    359 				/* No data. */
    360 				opaqueEv->opaque = new;
    361 				return (0);
    362 			}
    363 			if (pselect_errno == EBADF) {
    364 				for (x = 0; x <= ctx->fdMax; x++) {
    365 					struct stat sb;
    366 
    367 					if (FD_ISSET(x, &ctx->rdNext) == 0 &&
    368 					    FD_ISSET(x, &ctx->wrNext) == 0 &&
    369 					    FD_ISSET(x, &ctx->exNext) == 0)
    370 						continue;
    371 					if (fstat(x, &sb) == -1 &&
    372 					    errno == EBADF)
    373 						evPrintf(ctx, 1, "EBADF: %d\n",
    374 							 x);
    375 				}
    376 				abort();
    377 			}
    378 			EV_ERR(pselect_errno);
    379 		}
    380 		if (x == 0 && (nextTimer == NULL || !timerPast) &&
    381 		    (options & EV_POLL))
    382 			EV_ERR(EWOULDBLOCK);
    383 		ctx->fdCount = x;
    384 #ifdef EVENTLIB_TIME_CHECKS
    385 		ctx->lastFdCount = x;
    386 #endif
    387 	}
    388 	INSIST(nextTimer || ctx->fdCount);
    389 
    390 	/* Timers go first since we'd like them to be accurate. */
    391 	if (nextTimer && !timerPast) {
    392 		/* Has anything happened since we blocked? */
    393 		timerPast = (evCmpTime(nextTime, ctx->lastEventTime) <= 0);
    394 	}
    395 	if (nextTimer && timerPast) {
    396 		OKNEW(new);
    397 		new->type = Timer;
    398 		new->u.timer.this = nextTimer;
    399 		opaqueEv->opaque = new;
    400 		return (0);
    401 	}
    402 
    403 	/* No timers, so there should be a ready file descriptor. */
    404 	x = 0;
    405 	while (ctx->fdCount > 0) {
    406 		evFile *fid;
    407 		int fd, eventmask;
    408 
    409 		if (ctx->fdNext == NULL) {
    410 			if (++x == 2) {
    411 				/*
    412 				 * Hitting the end twice means that the last
    413 				 * select() found some FD's which have since
    414 				 * been deselected.
    415 				 *
    416 				 * On some systems, the count returned by
    417 				 * selects is the total number of bits in
    418 				 * all masks that are set, and on others it's
    419 				 * the number of fd's that have some bit set,
    420 				 * and on others, it's just broken.  We
    421 				 * always assume that it's the number of
    422 				 * bits set in all masks, because that's what
    423 				 * the man page says it should do, and
    424 				 * the worst that can happen is we do an
    425 				 * extra select().
    426 				 */
    427 				ctx->fdCount = 0;
    428 				break;
    429 			}
    430 			ctx->fdNext = ctx->files;
    431 		}
    432 		fid = ctx->fdNext;
    433 		ctx->fdNext = fid->next;
    434 
    435 		fd = fid->fd;
    436 		eventmask = 0;
    437 		if (FD_ISSET(fd, &ctx->rdLast))
    438 			eventmask |= EV_READ;
    439 		if (FD_ISSET(fd, &ctx->wrLast))
    440 			eventmask |= EV_WRITE;
    441 		if (FD_ISSET(fd, &ctx->exLast))
    442 			eventmask |= EV_EXCEPT;
    443 		eventmask &= fid->eventmask;
    444 		if (eventmask != 0) {
    445 			if ((eventmask & EV_READ) != 0) {
    446 				FD_CLR(fd, &ctx->rdLast);
    447 				ctx->fdCount--;
    448 			}
    449 			if ((eventmask & EV_WRITE) != 0) {
    450 				FD_CLR(fd, &ctx->wrLast);
    451 				ctx->fdCount--;
    452 			}
    453 			if ((eventmask & EV_EXCEPT) != 0) {
    454 				FD_CLR(fd, &ctx->exLast);
    455 				ctx->fdCount--;
    456 			}
    457 			OKNEW(new);
    458 			new->type = File;
    459 			new->u.file.this = fid;
    460 			new->u.file.eventmask = eventmask;
    461 			opaqueEv->opaque = new;
    462 			return (0);
    463 		}
    464 	}
    465 	if (ctx->fdCount < 0) {
    466 		/*
    467 		 * select()'s count is off on a number of systems, and
    468 		 * can result in fdCount < 0.
    469 		 */
    470 		evPrintf(ctx, 4, "fdCount < 0 (%d)\n", ctx->fdCount);
    471 		ctx->fdCount = 0;
    472 	}
    473 
    474 	/* We get here if the caller deselect()'s an FD. Gag me with a goto. */
    475 	goto again;
    476 }
    477 
    478 int
    479 evDispatch(evContext opaqueCtx, evEvent opaqueEv) {
    480 	evContext_p *ctx = opaqueCtx.opaque;
    481 	evEvent_p *ev = opaqueEv.opaque;
    482 #ifdef EVENTLIB_TIME_CHECKS
    483 	void *func;
    484 	struct timespec start_time;
    485 	struct timespec interval;
    486 #endif
    487 
    488 #ifdef EVENTLIB_TIME_CHECKS
    489 	if (ctx->debug > 0)
    490 		start_time = evNowTime();
    491 #endif
    492 	ctx->cur = ev;
    493 	switch (ev->type) {
    494 	    case Accept: {
    495 		evAccept *this = ev->u.accept.this;
    496 
    497 		evPrintf(ctx, 5,
    498 			"Dispatch.Accept: fd %d -> %d, func %p, uap %p\n",
    499 			 this->conn->fd, this->fd,
    500 			 this->conn->func, this->conn->uap);
    501 		errno = this->ioErrno;
    502 		(this->conn->func)(opaqueCtx, this->conn->uap, this->fd,
    503 				   &this->la, this->lalen,
    504 				   &this->ra, this->ralen);
    505 #ifdef EVENTLIB_TIME_CHECKS
    506 		func = this->conn->func;
    507 #endif
    508 		break;
    509 	    }
    510 	    case File: {
    511 		evFile *this = ev->u.file.this;
    512 		int eventmask = ev->u.file.eventmask;
    513 
    514 		evPrintf(ctx, 5,
    515 			"Dispatch.File: fd %d, mask 0x%x, func %p, uap %p\n",
    516 			 this->fd, this->eventmask, this->func, this->uap);
    517 		(this->func)(opaqueCtx, this->uap, this->fd, eventmask);
    518 #ifdef EVENTLIB_TIME_CHECKS
    519 		func = this->func;
    520 #endif
    521 		break;
    522 	    }
    523 	    case Stream: {
    524 		evStream *this = ev->u.stream.this;
    525 
    526 		evPrintf(ctx, 5,
    527 			 "Dispatch.Stream: fd %d, func %p, uap %p\n",
    528 			 this->fd, this->func, this->uap);
    529 		errno = this->ioErrno;
    530 		(this->func)(opaqueCtx, this->uap, this->fd, this->ioDone);
    531 #ifdef EVENTLIB_TIME_CHECKS
    532 		func = this->func;
    533 #endif
    534 		break;
    535 	    }
    536 	    case Timer: {
    537 		evTimer *this = ev->u.timer.this;
    538 
    539 		evPrintf(ctx, 5, "Dispatch.Timer: func %p, uap %p\n",
    540 			 this->func, this->uap);
    541 		(this->func)(opaqueCtx, this->uap, this->due, this->inter);
    542 #ifdef EVENTLIB_TIME_CHECKS
    543 		func = this->func;
    544 #endif
    545 		break;
    546 	    }
    547 	    case Wait: {
    548 		evWait *this = ev->u.wait.this;
    549 
    550 		evPrintf(ctx, 5,
    551 			 "Dispatch.Wait: tag %p, func %p, uap %p\n",
    552 			 this->tag, this->func, this->uap);
    553 		(this->func)(opaqueCtx, this->uap, this->tag);
    554 #ifdef EVENTLIB_TIME_CHECKS
    555 		func = this->func;
    556 #endif
    557 		break;
    558 	    }
    559 	    case Null: {
    560 		/* No work. */
    561 #ifdef EVENTLIB_TIME_CHECKS
    562 		func = NULL;
    563 #endif
    564 		break;
    565 	    }
    566 	    default: {
    567 		abort();
    568 	    }
    569 	}
    570 #ifdef EVENTLIB_TIME_CHECKS
    571 	if (ctx->debug > 0) {
    572 		interval = evSubTime(evNowTime(), start_time);
    573 		/*
    574 		 * Complain if it took longer than 50 milliseconds.
    575 		 *
    576 		 * We call getuid() to make an easy to find mark in a kernel
    577 		 * trace.
    578 		 */
    579 		if (interval.tv_sec > 0 || interval.tv_nsec > 50000000)
    580 			evPrintf(ctx, 1,
    581 			 "dispatch interval %u.%09u uid %d type %d func %p\n",
    582 				 interval.tv_sec, interval.tv_nsec,
    583 				 getuid(), ev->type, func);
    584 	}
    585 #endif
    586 	ctx->cur = NULL;
    587 	evDrop(opaqueCtx, opaqueEv);
    588 	return (0);
    589 }
    590 
    591 void
    592 evDrop(evContext opaqueCtx, evEvent opaqueEv) {
    593 	evContext_p *ctx = opaqueCtx.opaque;
    594 	evEvent_p *ev = opaqueEv.opaque;
    595 
    596 	switch (ev->type) {
    597 	    case Accept: {
    598 		FREE(ev->u.accept.this);
    599 		break;
    600 	    }
    601 	    case File: {
    602 		/* No work. */
    603 		break;
    604 	    }
    605 	    case Stream: {
    606 		evStreamID id;
    607 
    608 		id.opaque = ev->u.stream.this;
    609 		(void) evCancelRW(opaqueCtx, id);
    610 		break;
    611 	    }
    612 	    case Timer: {
    613 		evTimer *this = ev->u.timer.this;
    614 		evTimerID opaque;
    615 
    616 		/* Check to see whether the user func cleared the timer. */
    617 		if (heap_element(ctx->timers, this->index) != this) {
    618 			evPrintf(ctx, 5, "Dispatch.Timer: timer rm'd?\n");
    619 			break;
    620 		}
    621 		/*
    622 		 * Timer is still there.  Delete it if it has expired,
    623 		 * otherwise set it according to its next interval.
    624 		 */
    625 		if (this->inter.tv_sec == (time_t)0 &&
    626 		    this->inter.tv_nsec == 0L) {
    627 			opaque.opaque = this;
    628 			(void) evClearTimer(opaqueCtx, opaque);
    629 		} else {
    630 			opaque.opaque = this;
    631 			(void) evResetTimer(opaqueCtx, opaque, this->func,
    632 					    this->uap,
    633 					    evAddTime((this->mode & EV_TMR_RATE) ?
    634 						      this->due :
    635 						      ctx->lastEventTime,
    636 						      this->inter),
    637 					    this->inter);
    638 		}
    639 		break;
    640 	    }
    641 	    case Wait: {
    642 		FREE(ev->u.wait.this);
    643 		break;
    644 	    }
    645 	    case Null: {
    646 		/* No work. */
    647 		break;
    648 	    }
    649 	    default: {
    650 		abort();
    651 	    }
    652 	}
    653 	FREE(ev);
    654 }
    655 
    656 int
    657 evMainLoop(evContext opaqueCtx) {
    658 	evEvent event;
    659 	int x;
    660 
    661 	while ((x = evGetNext(opaqueCtx, &event, EV_WAIT)) == 0)
    662 		if ((x = evDispatch(opaqueCtx, event)) < 0)
    663 			break;
    664 	return (x);
    665 }
    666 
    667 int
    668 evHighestFD(evContext opaqueCtx) {
    669 	evContext_p *ctx = opaqueCtx.opaque;
    670 
    671 	return (ctx->highestFD);
    672 }
    673 
    674 void
    675 evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
    676 	va_list ap;
    677 
    678 	va_start(ap, fmt);
    679 	if (ctx->output != NULL && ctx->debug >= level) {
    680 		vfprintf(ctx->output, fmt, ap);
    681 		fflush(ctx->output);
    682 	}
    683 	va_end(ap);
    684 }
    685 
    686 int
    687 evSetOption(evContext *opaqueCtx, const char *option, int value) {
    688 	/* evContext_p *ctx = opaqueCtx->opaque; */
    689 
    690 	UNUSED(opaqueCtx);
    691 	UNUSED(value);
    692 #ifndef CLOCK_MONOTONIC
    693 	UNUSED(option);
    694 #endif
    695 
    696 #ifdef CLOCK_MONOTONIC
    697 	if (strcmp(option, "monotime") == 0) {
    698 		if (opaqueCtx  != NULL)
    699 			errno = EINVAL;
    700 		if (value == 0 || value == 1) {
    701 			__evOptMonoTime = value;
    702 			return (0);
    703 		} else {
    704 			errno = EINVAL;
    705 			return (-1);
    706 		}
    707 	}
    708 #endif
    709 	errno = ENOENT;
    710 	return (-1);
    711 }
    712 
    713 int
    714 evGetOption(evContext *opaqueCtx, const char *option, int *value) {
    715 	/* evContext_p *ctx = opaqueCtx->opaque; */
    716 
    717 	UNUSED(opaqueCtx);
    718 #ifndef CLOCK_MONOTONIC
    719 	UNUSED(value);
    720 	UNUSED(option);
    721 #endif
    722 
    723 #ifdef CLOCK_MONOTONIC
    724 	if (strcmp(option, "monotime") == 0) {
    725 		if (opaqueCtx  != NULL)
    726 			errno = EINVAL;
    727 		*value = __evOptMonoTime;
    728 		return (0);
    729 	}
    730 #endif
    731 	errno = ENOENT;
    732 	return (-1);
    733 }
    734 
    735 #if defined(NEED_PSELECT) || defined(USE_POLL)
    736 /* XXX needs to move to the porting library. */
    737 static int
    738 pselect(int nfds, void *rfds, void *wfds, void *efds,
    739 	struct timespec *tsp,
    740 	const sigset_t *sigmask)
    741 {
    742 	struct timeval tv, *tvp;
    743 	sigset_t sigs;
    744 	int n;
    745 #ifdef USE_POLL
    746 	int	polltimeout = INFTIM;
    747 	evContext_p	*ctx;
    748 	struct pollfd	*fds;
    749 	nfds_t		pnfds;
    750 
    751 	UNUSED(nfds);
    752 #endif /* USE_POLL */
    753 
    754 	if (tsp) {
    755 		tvp = &tv;
    756 		tv = evTimeVal(*tsp);
    757 #ifdef USE_POLL
    758 		polltimeout = 1000 * tv.tv_sec + tv.tv_usec / 1000;
    759 #endif /* USE_POLL */
    760 	} else
    761 		tvp = NULL;
    762 	if (sigmask)
    763 		sigprocmask(SIG_SETMASK, sigmask, &sigs);
    764 #ifndef USE_POLL
    765 	 n = select(nfds, rfds, wfds, efds, tvp);
    766 #else
    767         /*
    768 	 * rfds, wfds, and efds should all be from the same evContext_p,
    769 	 * so any of them will do. If they're all NULL, the caller is
    770 	 * presumably calling us to block.
    771 	 */
    772 	if (rfds != NULL)
    773 		ctx = ((__evEmulMask *)rfds)->ctx;
    774 	else if (wfds != NULL)
    775 		ctx = ((__evEmulMask *)wfds)->ctx;
    776 	else if (efds != NULL)
    777 		ctx = ((__evEmulMask *)efds)->ctx;
    778 	else
    779 		ctx = NULL;
    780 	if (ctx != NULL && ctx->fdMax != -1) {
    781 		fds = &(ctx->pollfds[ctx->firstfd]);
    782 		pnfds = ctx->fdMax - ctx->firstfd + 1;
    783 	} else {
    784 		fds = NULL;
    785 		pnfds = 0;
    786 	}
    787 	n = poll(fds, pnfds, polltimeout);
    788 	if (n > 0) {
    789 		int     i, e;
    790 
    791 		INSIST(ctx != NULL);
    792 		for (e = 0, i = ctx->firstfd; i <= ctx->fdMax; i++) {
    793 			if (ctx->pollfds[i].fd < 0)
    794 				continue;
    795 			if (FD_ISSET(i, &ctx->rdLast))
    796 				e++;
    797 			if (FD_ISSET(i, &ctx->wrLast))
    798 				e++;
    799 			if (FD_ISSET(i, &ctx->exLast))
    800 				e++;
    801 		}
    802 		n = e;
    803 	}
    804 #endif /* USE_POLL */
    805 	if (sigmask)
    806 		sigprocmask(SIG_SETMASK, &sigs, NULL);
    807 	if (tsp)
    808 		*tsp = evTimeSpec(tv);
    809 	return (n);
    810 }
    811 #endif
    812 
    813 #ifdef USE_POLL
    814 int
    815 evPollfdRealloc(evContext_p *ctx, int pollfd_chunk_size, int fd) {
    816 
    817 	int     i, maxnfds;
    818 	void	*pollfds, *fdTable;
    819 
    820 	if (fd < ctx->maxnfds)
    821 		return (0);
    822 
    823 	/* Don't allow ridiculously small values for pollfd_chunk_size */
    824 	if (pollfd_chunk_size < 20)
    825 		pollfd_chunk_size = 20;
    826 
    827 	maxnfds = (1 + (fd/pollfd_chunk_size)) * pollfd_chunk_size;
    828 
    829 	pollfds = realloc(ctx->pollfds, maxnfds * sizeof(*ctx->pollfds));
    830 	if (pollfds != NULL)
    831 		ctx->pollfds = pollfds;
    832 	fdTable = realloc(ctx->fdTable, maxnfds * sizeof(*ctx->fdTable));
    833 	if (fdTable != NULL)
    834 		ctx->fdTable = fdTable;
    835 
    836 	if (pollfds == NULL || fdTable == NULL) {
    837 		evPrintf(ctx, 2, "pollfd() realloc (%ld) failed\n",
    838 			 (long)maxnfds*sizeof(struct pollfd));
    839 		return (-1);
    840 	}
    841 
    842 	for (i = ctx->maxnfds; i < maxnfds; i++) {
    843 		ctx->pollfds[i].fd = -1;
    844 		ctx->pollfds[i].events = 0;
    845 		ctx->fdTable[i] = 0;
    846 	}
    847 
    848 	ctx->maxnfds = maxnfds;
    849 
    850 	return (0);
    851 }
    852 
    853 /* Find the appropriate 'events' or 'revents' field in the pollfds array */
    854 short *
    855 __fd_eventfield(int fd, __evEmulMask *maskp) {
    856 
    857 	evContext_p     *ctx = (evContext_p *)maskp->ctx;
    858 
    859 	if (!maskp->result || maskp->type == EV_WASNONBLOCKING)
    860 		return (&(ctx->pollfds[fd].events));
    861 	else
    862 		return (&(ctx->pollfds[fd].revents));
    863 }
    864 
    865 /* Translate to poll(2) event */
    866 short
    867 __poll_event(__evEmulMask *maskp) {
    868 
    869 	switch ((maskp)->type) {
    870 	case EV_READ:
    871 		return (POLLRDNORM);
    872 	case EV_WRITE:
    873 		return (POLLWRNORM);
    874 	case EV_EXCEPT:
    875 		return (POLLRDBAND | POLLPRI | POLLWRBAND);
    876 	case EV_WASNONBLOCKING:
    877 		return (POLLHUP);
    878 	default:
    879 		return (0);
    880 	}
    881 }
    882 
    883 /*
    884  * Clear the events corresponding to the specified mask. If this leaves
    885  * the events mask empty (apart from the POLLHUP bit), set the fd field
    886  * to -1 so that poll(2) will ignore this fd.
    887  */
    888 void
    889 __fd_clr(int fd, __evEmulMask *maskp) {
    890 
    891 	evContext_p     *ctx = maskp->ctx;
    892 
    893 	*__fd_eventfield(fd, maskp) &= ~__poll_event(maskp);
    894 	if ((ctx->pollfds[fd].events & ~POLLHUP) == 0) {
    895 		ctx->pollfds[fd].fd = -1;
    896 		if (fd == ctx->fdMax)
    897 			while (ctx->fdMax > ctx->firstfd &&
    898 			       ctx->pollfds[ctx->fdMax].fd < 0)
    899 				ctx->fdMax--;
    900 		if (fd == ctx->firstfd)
    901 			while (ctx->firstfd <= ctx->fdMax &&
    902 			       ctx->pollfds[ctx->firstfd].fd < 0)
    903 				ctx->firstfd++;
    904 		/*
    905 		 * Do we have a empty set of descriptors?
    906 		 */
    907 		if (ctx->firstfd > ctx->fdMax) {
    908 			ctx->fdMax = -1;
    909 			ctx->firstfd = 0;
    910 		}
    911 	}
    912 }
    913 
    914 /*
    915  * Set the events bit(s) corresponding to the specified mask. If the events
    916  * field has any other bits than POLLHUP set, also set the fd field so that
    917  * poll(2) will watch this fd.
    918  */
    919 void
    920 __fd_set(int fd, __evEmulMask *maskp) {
    921 
    922 	evContext_p     *ctx = maskp->ctx;
    923 
    924 	*__fd_eventfield(fd, maskp) |= __poll_event(maskp);
    925 	if ((ctx->pollfds[fd].events & ~POLLHUP) != 0) {
    926 		ctx->pollfds[fd].fd = fd;
    927 		if (fd < ctx->firstfd || ctx->fdMax == -1)
    928 			ctx->firstfd = fd;
    929 		if (fd > ctx->fdMax)
    930 			ctx->fdMax = fd;
    931 	}
    932 }
    933 #endif /* USE_POLL */
    934 
    935 /*! \file */
    936