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