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