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