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