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