1 /* $NetBSD: eventlib.c,v 1.1.1.1 2009/04/12 15:33:46 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 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 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 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 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 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 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 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 668 evHighestFD(evContext opaqueCtx) { 669 evContext_p *ctx = opaqueCtx.opaque; 670 671 return (ctx->highestFD); 672 } 673 674 void 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 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 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 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 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 * 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 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 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 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