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