xref: /netbsd-src/external/bsd/libbind/dist/isc/eventlib.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: eventlib.c,v 1.1.1.2 2012/09/09 16:08:00 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
evCreate(evContext * opaqueCtx)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
evSetDebug(evContext opaqueCtx,int level,FILE * output)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
evDestroy(evContext opaqueCtx)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
evGetNext(evContext opaqueCtx,evEvent * opaqueEv,int options)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
evDispatch(evContext opaqueCtx,evEvent opaqueEv)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
evDrop(evContext opaqueCtx,evEvent opaqueEv)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
evMainLoop(evContext opaqueCtx)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
evHighestFD(evContext opaqueCtx)668 evHighestFD(evContext opaqueCtx) {
669 	evContext_p *ctx = opaqueCtx.opaque;
670 
671 	return (ctx->highestFD);
672 }
673 
674 void
evPrintf(const evContext_p * ctx,int level,const char * fmt,...)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
evSetOption(evContext * opaqueCtx,const char * option,int value)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
evGetOption(evContext * opaqueCtx,const char * option,int * value)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
pselect(int nfds,void * rfds,void * wfds,void * efds,struct timespec * tsp,const sigset_t * sigmask)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
evPollfdRealloc(evContext_p * ctx,int pollfd_chunk_size,int fd)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 *
__fd_eventfield(int fd,__evEmulMask * maskp)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
__poll_event(__evEmulMask * maskp)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
__fd_clr(int fd,__evEmulMask * maskp)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
__fd_set(int fd,__evEmulMask * maskp)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