1 #include "first.h" 2 3 #include "fdevent_impl.h" 4 #include "fdevent.h" 5 #include "buffer.h" 6 #include "log.h" 7 8 #include <sys/types.h> 9 #include <unistd.h> 10 #include <errno.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #ifdef _WIN32 15 #include <winsock2.h> /* closesocket */ 16 #endif 17 18 #ifdef FDEVENT_USE_LINUX_EPOLL 19 __attribute_cold__ 20 static int fdevent_linux_sysepoll_init(struct fdevents *ev); 21 #endif 22 #ifdef FDEVENT_USE_FREEBSD_KQUEUE 23 __attribute_cold__ 24 static int fdevent_freebsd_kqueue_init(struct fdevents *ev); 25 #endif 26 #ifdef FDEVENT_USE_SOLARIS_PORT 27 __attribute_cold__ 28 static int fdevent_solaris_port_init(struct fdevents *ev); 29 #endif 30 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL 31 __attribute_cold__ 32 static int fdevent_solaris_devpoll_init(struct fdevents *ev); 33 #endif 34 #ifdef FDEVENT_USE_POLL 35 __attribute_cold__ 36 static int fdevent_poll_init(struct fdevents *ev); 37 #endif 38 #ifdef FDEVENT_USE_SELECT 39 __attribute_cold__ 40 static int fdevent_select_init(struct fdevents *ev); 41 #endif 42 43 44 int 45 fdevent_config (const char **event_handler_name, log_error_st *errh) 46 { 47 static const struct ev_map { fdevent_handler_t et; const char *name; } 48 event_handlers[] = 49 { 50 /* - epoll is most reliable 51 * - select works everywhere 52 */ 53 #ifdef FDEVENT_USE_LINUX_EPOLL 54 { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" }, 55 { FDEVENT_HANDLER_LINUX_SYSEPOLL, "epoll" }, 56 #endif 57 #ifdef FDEVENT_USE_SOLARIS_PORT 58 { FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" }, 59 #endif 60 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL 61 { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" }, 62 #endif 63 #ifdef FDEVENT_USE_FREEBSD_KQUEUE 64 { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" }, 65 { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" }, 66 #endif 67 #ifdef FDEVENT_USE_POLL 68 { FDEVENT_HANDLER_POLL, "poll" }, 69 #endif 70 #ifdef FDEVENT_USE_SELECT 71 { FDEVENT_HANDLER_SELECT, "select" }, 72 #endif 73 { FDEVENT_HANDLER_UNSET, NULL } 74 }; 75 76 const char *event_handler = *event_handler_name; 77 fdevent_handler_t et = FDEVENT_HANDLER_UNSET; 78 79 if (NULL != event_handler && 0 == strcmp(event_handler, "libev")) 80 event_handler = NULL; 81 #ifdef FDEVENT_USE_POLL 82 if (NULL != event_handler && 0 == strcmp(event_handler, "select")) 83 event_handler = "poll"; 84 #endif 85 86 if (NULL == event_handler) { 87 /* choose a good default 88 * 89 * the event_handler list is sorted by 'goodness' 90 * taking the first available should be the best solution 91 */ 92 et = event_handlers[0].et; 93 *event_handler_name = event_handlers[0].name; 94 95 if (FDEVENT_HANDLER_UNSET == et) { 96 log_error(errh, __FILE__, __LINE__, 97 "sorry, there is no event handler for this system"); 98 99 return -1; 100 } 101 } 102 else { 103 /* 104 * User override 105 */ 106 107 for (uint32_t i = 0; event_handlers[i].name; ++i) { 108 if (0 == strcmp(event_handlers[i].name, event_handler)) { 109 et = event_handlers[i].et; 110 break; 111 } 112 } 113 114 if (FDEVENT_HANDLER_UNSET == et) { 115 log_error(errh, __FILE__, __LINE__, 116 "the selected event-handler in unknown or not supported: %s", 117 event_handler); 118 return -1; 119 } 120 } 121 122 return et; 123 } 124 125 126 const char * 127 fdevent_show_event_handlers (void) 128 { 129 return 130 "\nEvent Handlers:\n\n" 131 #ifdef FDEVENT_USE_SELECT 132 "\t+ select (generic)\n" 133 #else 134 "\t- select (generic)\n" 135 #endif 136 #ifdef FDEVENT_USE_POLL 137 "\t+ poll (Unix)\n" 138 #else 139 "\t- poll (Unix)\n" 140 #endif 141 #ifdef FDEVENT_USE_LINUX_EPOLL 142 "\t+ epoll (Linux)\n" 143 #else 144 "\t- epoll (Linux)\n" 145 #endif 146 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL 147 "\t+ /dev/poll (Solaris)\n" 148 #else 149 "\t- /dev/poll (Solaris)\n" 150 #endif 151 #ifdef FDEVENT_USE_SOLARIS_PORT 152 "\t+ eventports (Solaris)\n" 153 #else 154 "\t- eventports (Solaris)\n" 155 #endif 156 #ifdef FDEVENT_USE_FREEBSD_KQUEUE 157 "\t+ kqueue (FreeBSD)\n" 158 #else 159 "\t- kqueue (FreeBSD)\n" 160 #endif 161 ; 162 } 163 164 165 fdevents * 166 fdevent_init (const char *event_handler, int *max_fds, int *cur_fds, log_error_st *errh) 167 { 168 fdevents *ev; 169 uint32_t maxfds = (0 != *max_fds) 170 ? (uint32_t)*max_fds 171 : 4096; 172 int type = fdevent_config(&event_handler, errh); 173 if (type <= 0) return NULL; 174 175 fdevent_socket_nb_cloexec_init(); 176 177 #ifdef FDEVENT_USE_SELECT 178 /* select limits itself 179 * as it is a hard limit and will lead to a segfault we add some safety 180 * */ 181 if (type == FDEVENT_HANDLER_SELECT) { 182 if (maxfds > (uint32_t)FD_SETSIZE - 200) 183 maxfds = (uint32_t)FD_SETSIZE - 200; 184 } 185 #endif 186 *max_fds = (int)maxfds; 187 ++maxfds; /*(+1 for event-handler fd)*/ 188 189 ev = ck_calloc(1, sizeof(*ev)); 190 ev->errh = errh; 191 ev->cur_fds = cur_fds; 192 ev->event_handler = event_handler; 193 ev->fdarray = ck_calloc(maxfds, sizeof(*ev->fdarray)); 194 ev->maxfds = maxfds; 195 196 switch(type) { 197 #ifdef FDEVENT_USE_POLL 198 case FDEVENT_HANDLER_POLL: 199 if (0 == fdevent_poll_init(ev)) return ev; 200 break; 201 #endif 202 #ifdef FDEVENT_USE_SELECT 203 case FDEVENT_HANDLER_SELECT: 204 if (0 == fdevent_select_init(ev)) return ev; 205 break; 206 #endif 207 #ifdef FDEVENT_USE_LINUX_EPOLL 208 case FDEVENT_HANDLER_LINUX_SYSEPOLL: 209 if (0 == fdevent_linux_sysepoll_init(ev)) return ev; 210 break; 211 #endif 212 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL 213 case FDEVENT_HANDLER_SOLARIS_DEVPOLL: 214 if (0 == fdevent_solaris_devpoll_init(ev)) return ev; 215 break; 216 #endif 217 #ifdef FDEVENT_USE_SOLARIS_PORT 218 case FDEVENT_HANDLER_SOLARIS_PORT: 219 if (0 == fdevent_solaris_port_init(ev)) return ev; 220 break; 221 #endif 222 #ifdef FDEVENT_USE_FREEBSD_KQUEUE 223 case FDEVENT_HANDLER_FREEBSD_KQUEUE: 224 if (0 == fdevent_freebsd_kqueue_init(ev)) return ev; 225 break; 226 #endif 227 /*case FDEVENT_HANDLER_UNSET:*/ 228 default: 229 break; 230 } 231 232 free(ev->fdarray); 233 free(ev); 234 235 log_error(errh, __FILE__, __LINE__, 236 "event-handler failed: %s; " 237 "try to set server.event-handler = \"poll\" or \"select\"", 238 event_handler); 239 return NULL; 240 } 241 242 243 void 244 fdevent_free (fdevents *ev) 245 { 246 if (!ev) return; 247 if (ev->free) ev->free(ev); 248 249 for (uint32_t i = 0; i < ev->maxfds; ++i) { 250 /* (fdevent_sched_run() should already have been run, 251 * but take reasonable precautions anyway) */ 252 if (ev->fdarray[i]) 253 free((fdnode *)((uintptr_t)ev->fdarray[i] & ~0x3)); 254 } 255 256 free(ev->fdarray); 257 free(ev); 258 } 259 260 261 int 262 fdevent_reset (fdevents *ev) 263 { 264 int rc = (NULL != ev->reset) ? ev->reset(ev) : 0; 265 if (-1 == rc) { 266 log_error(ev->errh, __FILE__, __LINE__, 267 "event-handler failed: %s; " 268 "try to set server.event-handler = \"poll\" or \"select\"", 269 ev->event_handler ? ev->event_handler : ""); 270 } 271 return rc; 272 } 273 274 275 static void 276 fdevent_sched_run (fdevents * const ev) 277 { 278 for (fdnode *fdn = ev->pendclose; fdn; ) { 279 int fd, rc; 280 #ifdef _WIN32 281 rc = (uintptr_t)fdn & 0x3; 282 #endif 283 fdn = (fdnode *)((uintptr_t)fdn & ~0x3); 284 fd = fdn->fd; 285 #ifdef _WIN32 286 if (rc == 0x1) { 287 rc = closesocket(fd); 288 } 289 else if (rc == 0x2) { 290 rc = close(fd); 291 } 292 #else 293 rc = close(fd); 294 #endif 295 296 if (0 != rc) { 297 log_perror(ev->errh, __FILE__, __LINE__, "close failed %d", fd); 298 } 299 else { 300 --(*ev->cur_fds); 301 } 302 303 fdnode * const fdn_tmp = fdn; 304 fdn = (fdnode *)fdn->ctx; /* next */ 305 /*(fdevent_unregister)*/ 306 free(fdn_tmp); /*fdnode_free(fdn_tmp);*/ 307 ev->fdarray[fd] = NULL; 308 } 309 ev->pendclose = NULL; 310 } 311 312 313 int 314 fdevent_poll (fdevents * const ev, const int timeout_ms) 315 { 316 const int n = ev->poll(ev, ev->pendclose ? 0 : timeout_ms); 317 if (n >= 0) 318 fdevent_sched_run(ev); 319 else if (errno != EINTR) 320 log_perror(ev->errh, __FILE__, __LINE__, "fdevent_poll failed"); 321 return n; 322 } 323 324 325 #ifdef FDEVENT_USE_LINUX_EPOLL 326 327 #include <sys/epoll.h> 328 329 static int 330 fdevent_linux_sysepoll_event_del (fdevents *ev, fdnode *fdn) 331 { 332 return epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fdn->fd, NULL); 333 } 334 335 static int 336 fdevent_linux_sysepoll_event_set (fdevents *ev, fdnode *fdn, int events) 337 { 338 int op = (-1 == fdn->fde_ndx) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; 339 int fd = fdn->fde_ndx = fdn->fd; 340 struct epoll_event ep; 341 #ifndef EPOLLRDHUP 342 events &= ~FDEVENT_RDHUP; 343 #endif 344 ep.events = events | EPOLLERR | EPOLLHUP; 345 ep.data.ptr = fdn; 346 return epoll_ctl(ev->epoll_fd, op, fd, &ep); 347 } 348 349 static int 350 fdevent_linux_sysepoll_poll (fdevents * const ev, int timeout_ms) 351 { 352 struct epoll_event * const restrict epoll_events = ev->epoll_events; 353 int n = epoll_wait(ev->epoll_fd, epoll_events, ev->maxfds, timeout_ms); 354 for (int i = 0; i < n; ++i) { 355 fdnode * const fdn = (fdnode *)epoll_events[i].data.ptr; 356 int revents = epoll_events[i].events; 357 if ((fdevent_handler)NULL != fdn->handler) 358 (*fdn->handler)(fdn->ctx, revents); 359 } 360 return n; 361 } 362 363 __attribute_cold__ 364 static void 365 fdevent_linux_sysepoll_free (fdevents *ev) 366 { 367 close(ev->epoll_fd); 368 free(ev->epoll_events); 369 } 370 371 __attribute_cold__ 372 static int 373 fdevent_linux_sysepoll_init (fdevents *ev) 374 { 375 force_assert(EPOLLIN == FDEVENT_IN); 376 force_assert(EPOLLPRI == FDEVENT_PRI); 377 force_assert(EPOLLOUT == FDEVENT_OUT); 378 force_assert(EPOLLERR == FDEVENT_ERR); 379 force_assert(EPOLLHUP == FDEVENT_HUP); 380 #ifdef EPOLLRDHUP 381 force_assert(EPOLLRDHUP == FDEVENT_RDHUP); 382 #endif 383 384 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL; 385 ev->event_set = fdevent_linux_sysepoll_event_set; 386 ev->event_del = fdevent_linux_sysepoll_event_del; 387 ev->poll = fdevent_linux_sysepoll_poll; 388 ev->free = fdevent_linux_sysepoll_free; 389 390 #ifdef EPOLL_CLOEXEC 391 if (-1 == (ev->epoll_fd = epoll_create1(EPOLL_CLOEXEC))) return -1; 392 #else 393 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) return -1; 394 fdevent_setfd_cloexec(ev->epoll_fd); 395 #endif 396 397 ev->epoll_events = ck_calloc(ev->maxfds, sizeof(*ev->epoll_events)); 398 399 return 0; 400 } 401 402 #endif /* FDEVENT_USE_LINUX_EPOLL */ 403 404 405 #ifdef FDEVENT_USE_FREEBSD_KQUEUE 406 407 #include <sys/event.h> 408 #include <sys/time.h> 409 #include <fcntl.h> 410 411 static int 412 fdevent_freebsd_kqueue_event_del (fdevents *ev, fdnode *fdn) 413 { 414 struct kevent kev[2]; 415 struct timespec ts = {0, 0}; 416 int fd = fdn->fd; 417 int n = 0; 418 int oevents = fdn->events; 419 420 if (oevents & FDEVENT_IN) { 421 EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn); 422 n++; 423 } 424 if (oevents & FDEVENT_OUT) { 425 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn); 426 n++; 427 } 428 429 return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0; 430 /*(kevent() changelist still processed on EINTR, 431 * but EINTR should not be received since 0 == nevents)*/ 432 } 433 434 static int 435 fdevent_freebsd_kqueue_event_set (fdevents *ev, fdnode *fdn, int events) 436 { 437 struct kevent kev[2]; 438 struct timespec ts = {0, 0}; 439 int fd = fdn->fde_ndx = fdn->fd; 440 int n = 0; 441 int oevents = fdn->events; 442 int addevents = events & ~oevents; 443 int delevents = ~events & oevents; 444 445 if (addevents & FDEVENT_IN) { 446 EV_SET(&kev[n], fd, EVFILT_READ, EV_ADD, 0, 0, fdn); 447 n++; 448 } 449 else if (delevents & FDEVENT_IN) { 450 EV_SET(&kev[n], fd, EVFILT_READ, EV_DELETE, 0, 0, fdn); 451 n++; 452 } 453 454 if (addevents & FDEVENT_OUT) { 455 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_ADD, 0, 0, fdn); 456 n++; 457 } 458 else if (delevents & FDEVENT_OUT) { 459 EV_SET(&kev[n], fd, EVFILT_WRITE, EV_DELETE, 0, 0, fdn); 460 n++; 461 } 462 463 return (0 != n) ? kevent(ev->kq_fd, kev, n, NULL, 0, &ts) : 0; 464 /*(kevent() changelist still processed on EINTR, 465 * but EINTR should not be received since 0 == nevents)*/ 466 } 467 468 static int 469 fdevent_freebsd_kqueue_poll (fdevents * const ev, int timeout_ms) 470 { 471 struct timespec ts; 472 ts.tv_sec = timeout_ms / 1000; 473 ts.tv_nsec = (timeout_ms % 1000) * 1000000; 474 475 struct kevent * const restrict kq_results = ev->kq_results; 476 const int n = kevent(ev->kq_fd, NULL, 0, kq_results, ev->maxfds, &ts); 477 478 for (int i = 0; i < n; ++i) { 479 fdnode * const fdn = (fdnode *)kq_results[i].udata; 480 int filt = kq_results[i].filter; 481 int e = kq_results[i].flags; 482 if ((fdevent_handler)NULL != fdn->handler) { 483 int revents = (filt == EVFILT_READ) ? FDEVENT_IN : FDEVENT_OUT; 484 if (e & EV_EOF) 485 revents |= (filt == EVFILT_READ ? FDEVENT_RDHUP : FDEVENT_HUP); 486 if (e & EV_ERROR) 487 revents |= FDEVENT_ERR; 488 (*fdn->handler)(fdn->ctx, revents); 489 } 490 } 491 return n; 492 } 493 494 __attribute_cold__ 495 static int 496 fdevent_freebsd_kqueue_reset (fdevents *ev) 497 { 498 #ifdef __NetBSD__ 499 ev->kq_fd = kqueue1(O_NONBLOCK|O_CLOEXEC|O_NOSIGPIPE); 500 return (-1 != ev->kq_fd) ? 0 : -1; 501 #else 502 ev->kq_fd = kqueue(); 503 if (-1 == ev->kq_fd) return -1; 504 fdevent_setfd_cloexec(ev->kq_fd); 505 return 0; 506 #endif 507 } 508 509 __attribute_cold__ 510 static void 511 fdevent_freebsd_kqueue_free (fdevents *ev) 512 { 513 close(ev->kq_fd); 514 free(ev->kq_results); 515 } 516 517 __attribute_cold__ 518 static int 519 fdevent_freebsd_kqueue_init (fdevents *ev) 520 { 521 ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE; 522 ev->event_set = fdevent_freebsd_kqueue_event_set; 523 ev->event_del = fdevent_freebsd_kqueue_event_del; 524 ev->poll = fdevent_freebsd_kqueue_poll; 525 ev->reset = fdevent_freebsd_kqueue_reset; 526 ev->free = fdevent_freebsd_kqueue_free; 527 ev->kq_fd = -1; 528 ev->kq_results = ck_calloc(ev->maxfds, sizeof(*ev->kq_results)); 529 return 0; 530 } 531 532 #endif /* FDEVENT_USE_FREEBSD_KQUEUE */ 533 534 535 #ifdef FDEVENT_USE_SOLARIS_PORT 536 537 #include <sys/poll.h> 538 #include <fcntl.h> 539 540 static int 541 fdevent_solaris_port_event_del (fdevents *ev, fdnode *fdn) 542 { 543 return port_dissociate(ev->port_fd, PORT_SOURCE_FD, fdn->fd); 544 } 545 546 static int 547 fdevent_solaris_port_event_set (fdevents *ev, fdnode *fdn, int events) 548 { 549 int fd = fdn->fde_ndx = fdn->fd; 550 intptr_t ud = events & (POLLIN|POLLOUT); 551 return port_associate(ev->port_fd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud); 552 } 553 554 /* if there is any error it will return the return values of port_getn, 555 * otherwise it will return number of events */ 556 static int 557 fdevent_solaris_port_poll (fdevents *ev, int timeout_ms) 558 { 559 const int pfd = ev->port_fd; 560 int ret; 561 unsigned int available_events, wait_for_events = 0; 562 563 struct timespec timeout; 564 565 timeout.tv_sec = timeout_ms/1000L; 566 timeout.tv_nsec = (timeout_ms % 1000L) * 1000000L; 567 568 /* get the number of file descriptors with events */ 569 if ((ret = port_getn(pfd, ev->port_events, 0, &wait_for_events, &timeout)) < 0) return ret; 570 571 /* wait for at least one event */ 572 if (0 == wait_for_events) wait_for_events = 1; 573 574 available_events = wait_for_events; 575 576 /* get the events of the file descriptors */ 577 if ((ret = port_getn(pfd, ev->port_events, ev->maxfds, &available_events, &timeout)) < 0) { 578 /* if errno == ETIME and available_event == wait_for_events we didn't get any events */ 579 /* for other errors we didn't get any events either */ 580 if (!(errno == ETIME && wait_for_events != available_events)) return ret; 581 } 582 583 for (int i = 0; i < (int)available_events; ++i) { 584 int fd = (int)ev->port_events[i].portev_object; 585 fdnode * const fdn = ev->fdarray[fd]; 586 const intptr_t ud = (intptr_t)ev->port_events[i].portev_user; 587 int revents = ev->port_events[i].portev_events; 588 if (0 == ((uintptr_t)fdn & 0x3)) { 589 if (port_associate(pfd,PORT_SOURCE_FD,fd,(int)ud,(void*)ud) < 0) 590 log_error(ev->errh,__FILE__,__LINE__,"port_associate failed"); 591 (*fdn->handler)(fdn->ctx, revents); 592 } 593 else { 594 fdn->fde_ndx = -1; 595 } 596 } 597 return available_events; 598 } 599 600 __attribute_cold__ 601 static void 602 fdevent_solaris_port_free (fdevents *ev) 603 { 604 close(ev->port_fd); 605 free(ev->port_events); 606 } 607 608 __attribute_cold__ 609 static int 610 fdevent_solaris_port_init (fdevents *ev) 611 { 612 force_assert(POLLIN == FDEVENT_IN); 613 force_assert(POLLPRI == FDEVENT_PRI); 614 force_assert(POLLOUT == FDEVENT_OUT); 615 force_assert(POLLERR == FDEVENT_ERR); 616 force_assert(POLLHUP == FDEVENT_HUP); 617 force_assert(POLLNVAL == FDEVENT_NVAL); 618 #ifdef POLLRDHUP 619 force_assert(POLLRDHUP == FDEVENT_RDHUP); 620 #endif 621 622 ev->type = FDEVENT_HANDLER_SOLARIS_PORT; 623 ev->event_set = fdevent_solaris_port_event_set; 624 ev->event_del = fdevent_solaris_port_event_del; 625 ev->poll = fdevent_solaris_port_poll; 626 ev->free = fdevent_solaris_port_free; 627 ev->port_events = ck_calloc(ev->maxfds, sizeof(*ev->port_events)); 628 629 if ((ev->port_fd = port_create()) < 0) return -1; 630 631 return 0; 632 } 633 634 #endif /* FDEVENT_USE_SOLARIS_PORT */ 635 636 637 #ifdef FDEVENT_USE_SOLARIS_DEVPOLL 638 639 #include <sys/devpoll.h> 640 #include <sys/ioctl.h> 641 #include <fcntl.h> 642 643 static int 644 fdevent_solaris_devpoll_event_del (fdevents *ev, fdnode *fdn) 645 { 646 struct pollfd pfd; 647 pfd.fd = fdn->fd; 648 pfd.events = POLLREMOVE; 649 pfd.revents = 0; 650 return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1; 651 } 652 653 static int 654 fdevent_solaris_devpoll_event_set (fdevents *ev, fdnode *fdn, int events) 655 { 656 struct pollfd pfd; 657 pfd.fd = fdn->fde_ndx = fdn->fd; 658 #ifndef POLLRDHUP 659 events &= ~FDEVENT_RDHUP; 660 #endif 661 pfd.events = events; 662 pfd.revents = 0; 663 return (-1 != write(ev->devpoll_fd, &pfd, sizeof(pfd))) ? 0 : -1; 664 } 665 666 static int 667 fdevent_solaris_devpoll_poll (fdevents *ev, int timeout_ms) 668 { 669 fdnode ** const fdarray = ev->fdarray; 670 struct pollfd * const devpollfds = ev->devpollfds; 671 struct dvpoll dopoll; 672 673 dopoll.dp_timeout = timeout_ms; 674 dopoll.dp_nfds = ev->maxfds - 1; 675 dopoll.dp_fds = devpollfds; 676 677 const int n = ioctl(ev->devpoll_fd, DP_POLL, &dopoll); 678 679 for (int i = 0; i < n; ++i) { 680 fdnode * const fdn = fdarray[devpollfds[i].fd]; 681 int revents = devpollfds[i].revents; 682 if (0 == ((uintptr_t)fdn & 0x3)) 683 (*fdn->handler)(fdn->ctx, revents); 684 } 685 return n; 686 } 687 688 __attribute_cold__ 689 static int 690 fdevent_solaris_devpoll_reset (fdevents *ev) 691 { 692 /* a forked process does only inherit the filedescriptor, 693 * but every operation on the device will lead to a EACCES */ 694 ev->devpoll_fd = fdevent_open_cloexec("/dev/poll", 1, O_RDWR, 0); 695 return (ev->devpoll_fd >= 0) ? 0 : -1; 696 } 697 698 __attribute_cold__ 699 static void 700 fdevent_solaris_devpoll_free (fdevents *ev) 701 { 702 free(ev->devpollfds); 703 close(ev->devpoll_fd); 704 } 705 706 __attribute_cold__ 707 static int 708 fdevent_solaris_devpoll_init (fdevents *ev) 709 { 710 force_assert(POLLIN == FDEVENT_IN); 711 force_assert(POLLPRI == FDEVENT_PRI); 712 force_assert(POLLOUT == FDEVENT_OUT); 713 force_assert(POLLERR == FDEVENT_ERR); 714 force_assert(POLLHUP == FDEVENT_HUP); 715 force_assert(POLLNVAL == FDEVENT_NVAL); 716 #ifdef POLLRDHUP 717 force_assert(POLLRDHUP == FDEVENT_RDHUP); 718 #endif 719 720 ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL; 721 ev->event_set = fdevent_solaris_devpoll_event_set; 722 ev->event_del = fdevent_solaris_devpoll_event_del; 723 ev->poll = fdevent_solaris_devpoll_poll; 724 ev->reset = fdevent_solaris_devpoll_reset; 725 ev->free = fdevent_solaris_devpoll_free; 726 ev->devpoll_fd = -1; 727 ev->devpollfds = ck_calloc(ev->maxfds, sizeof(*ev->devpollfds)); 728 return 0; 729 } 730 731 #endif /* FDEVENT_USE_SOLARIS_DEVPOLL */ 732 733 734 #ifdef FDEVENT_USE_POLL 735 736 #ifdef HAVE_POLL_H 737 #include <poll.h> 738 #else 739 #include <sys/poll.h> 740 #endif 741 742 static int 743 fdevent_poll_event_del (fdevents *ev, fdnode *fdn) 744 { 745 int fd = fdn->fd; 746 int k = fdn->fde_ndx; 747 if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd) 748 return (errno = EINVAL, -1); 749 750 ev->pollfds[k].fd = -1; 751 /* ev->pollfds[k].events = 0; */ 752 /* ev->pollfds[k].revents = 0; */ 753 754 if (ev->unused.size == ev->unused.used) { 755 ck_realloc_u32((void **)&ev->unused.ptr, ev->unused.size, 756 16, sizeof(*ev->unused.ptr)); 757 ev->unused.size += 16; 758 } 759 760 ev->unused.ptr[ev->unused.used++] = k; 761 762 return 0; 763 } 764 765 static int 766 fdevent_poll_event_set (fdevents *ev, fdnode *fdn, int events) 767 { 768 int fd = fdn->fd; 769 int k = fdn->fde_ndx; 770 771 #ifndef POLLRDHUP 772 events &= ~FDEVENT_RDHUP; 773 #endif 774 775 if (k >= 0) { 776 if ((uint32_t)k >= ev->used || ev->pollfds[k].fd != fd) 777 return (errno = EINVAL, -1); 778 ev->pollfds[k].events = events; 779 return 0; 780 } 781 782 if (ev->unused.used > 0) { 783 k = ev->unused.ptr[--ev->unused.used]; 784 } 785 else { 786 if (ev->size == ev->used) { 787 ck_realloc_u32((void **)&ev->pollfds, ev->size, 788 16, sizeof(*ev->pollfds)); 789 ev->size += 16; 790 } 791 792 k = ev->used++; 793 } 794 795 fdn->fde_ndx = k; 796 ev->pollfds[k].fd = fd; 797 ev->pollfds[k].events = events; 798 799 return 0; 800 } 801 802 static int 803 fdevent_poll_poll (fdevents *ev, int timeout_ms) 804 { 805 struct pollfd * const restrict pfds = ev->pollfds; 806 fdnode ** const fdarray = ev->fdarray; 807 const int n = poll(pfds, ev->used, timeout_ms); 808 for (int i = 0, m = 0; m < n; ++i) { 809 if (0 == pfds[i].revents) continue; 810 fdnode *fdn = fdarray[pfds[i].fd]; 811 if (0 == ((uintptr_t)fdn & 0x3)) 812 (*fdn->handler)(fdn->ctx, pfds[i].revents); 813 ++m; 814 } 815 return n; 816 } 817 818 __attribute_cold__ 819 static void 820 fdevent_poll_free (fdevents *ev) 821 { 822 free(ev->pollfds); 823 if (ev->unused.ptr) free(ev->unused.ptr); 824 } 825 826 __attribute_cold__ 827 static int 828 fdevent_poll_init (fdevents *ev) 829 { 830 force_assert(POLLIN == FDEVENT_IN); 831 force_assert(POLLPRI == FDEVENT_PRI); 832 force_assert(POLLOUT == FDEVENT_OUT); 833 force_assert(POLLERR == FDEVENT_ERR); 834 force_assert(POLLHUP == FDEVENT_HUP); 835 force_assert(POLLNVAL == FDEVENT_NVAL); 836 #ifdef POLLRDHUP 837 force_assert(POLLRDHUP == FDEVENT_RDHUP); 838 #endif 839 840 ev->type = FDEVENT_HANDLER_POLL; 841 ev->event_set = fdevent_poll_event_set; 842 ev->event_del = fdevent_poll_event_del; 843 ev->poll = fdevent_poll_poll; 844 ev->free = fdevent_poll_free; 845 return 0; 846 } 847 848 #endif /* FDEVENT_USE_POLL */ 849 850 851 #ifdef FDEVENT_USE_SELECT 852 853 #include "sys-time.h" 854 855 __attribute_cold__ 856 static int 857 fdevent_select_reset (fdevents *ev) 858 { 859 FD_ZERO(&(ev->select_set_read)); 860 FD_ZERO(&(ev->select_set_write)); 861 FD_ZERO(&(ev->select_set_error)); 862 ev->select_max_fd = -1; 863 return 0; 864 } 865 866 static int 867 fdevent_select_event_del (fdevents *ev, fdnode *fdn) 868 { 869 int fd = fdn->fd; 870 FD_CLR(fd, &(ev->select_set_read)); 871 FD_CLR(fd, &(ev->select_set_write)); 872 FD_CLR(fd, &(ev->select_set_error)); 873 return 0; 874 } 875 876 static int 877 fdevent_select_event_set (fdevents *ev, fdnode *fdn, int events) 878 { 879 int fd = fdn->fde_ndx = fdn->fd; 880 881 /* we should be protected by max-fds, but you never know */ 882 force_assert(fd < ((int)FD_SETSIZE)); 883 884 if (events & FDEVENT_IN) 885 FD_SET(fd, &(ev->select_set_read)); 886 else 887 FD_CLR(fd, &(ev->select_set_read)); 888 889 if (events & FDEVENT_OUT) 890 FD_SET(fd, &(ev->select_set_write)); 891 else 892 FD_CLR(fd, &(ev->select_set_write)); 893 894 FD_SET(fd, &(ev->select_set_error)); 895 896 if (fd > ev->select_max_fd) ev->select_max_fd = fd; 897 898 return 0; 899 } 900 901 static int 902 fdevent_select_event_get_revent (const fdevents *ev, int ndx) 903 { 904 int revents = 0; 905 if (FD_ISSET(ndx, &ev->select_read)) revents |= FDEVENT_IN; 906 if (FD_ISSET(ndx, &ev->select_write)) revents |= FDEVENT_OUT; 907 if (FD_ISSET(ndx, &ev->select_error)) revents |= FDEVENT_ERR; 908 return revents; 909 } 910 911 static int 912 fdevent_select_event_next_fdndx (const fdevents *ev, int ndx) 913 { 914 const int max_fd = ev->select_max_fd + 1; 915 for (int i = (ndx < 0) ? 0 : ndx + 1; i < max_fd; ++i) { 916 if (FD_ISSET(i, &(ev->select_read))) return i; 917 if (FD_ISSET(i, &(ev->select_write))) return i; 918 if (FD_ISSET(i, &(ev->select_error))) return i; 919 } 920 921 return -1; 922 } 923 924 static int 925 fdevent_select_poll (fdevents *ev, int timeout_ms) 926 { 927 int n; 928 struct timeval tv; 929 930 tv.tv_sec = timeout_ms / 1000; 931 tv.tv_usec = (timeout_ms % 1000) * 1000; 932 933 ev->select_read = ev->select_set_read; 934 ev->select_write = ev->select_set_write; 935 ev->select_error = ev->select_set_error; 936 937 n = select(ev->select_max_fd + 1, 938 &ev->select_read, &ev->select_write, &ev->select_error, &tv); 939 for (int ndx = -1, i = 0; i < n; ++i) { 940 fdnode *fdn; 941 ndx = fdevent_select_event_next_fdndx(ev, ndx); 942 if (-1 == ndx) break; 943 fdn = ev->fdarray[ndx]; 944 if (0 == ((uintptr_t)fdn & 0x3)) { 945 int revents = fdevent_select_event_get_revent(ev, ndx); 946 (*fdn->handler)(fdn->ctx, revents); 947 } 948 } 949 return n; 950 } 951 952 __attribute_cold__ 953 static int fdevent_select_init (fdevents *ev) 954 { 955 ev->type = FDEVENT_HANDLER_SELECT; 956 ev->event_set = fdevent_select_event_set; 957 ev->event_del = fdevent_select_event_del; 958 ev->poll = fdevent_select_poll; 959 ev->reset = fdevent_select_reset; 960 return 0; 961 } 962 963 #endif /* FDEVENT_USE_SELECT */ 964