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