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