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