1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * eloop - portable event based main loop. 4 * Copyright (c) 2006-2020 Roy Marples <roy@marples.name> 5 * All rights reserved. 6 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/time.h> 30 31 #include <assert.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <poll.h> 35 #include <signal.h> 36 #include <stdint.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 /* config.h should define HAVE_PPOLL, etc. */ 42 #if defined(HAVE_CONFIG_H) && !defined(NO_CONFIG_H) 43 #include "config.h" 44 #endif 45 46 #if defined(HAVE_PPOLL) 47 #elif defined(HAVE_POLLTS) 48 #define ppoll pollts 49 #elif !defined(HAVE_PSELECT) 50 #pragma message("Compiling eloop with pselect(2) support.") 51 #define HAVE_PSELECT 52 #define ppoll eloop_ppoll 53 #endif 54 55 #include "eloop.h" 56 57 #ifndef UNUSED 58 #define UNUSED(a) (void)((a)) 59 #endif 60 #ifndef __unused 61 #ifdef __GNUC__ 62 #define __unused __attribute__((__unused__)) 63 #else 64 #define __unused 65 #endif 66 #endif 67 68 #ifdef HAVE_PSELECT 69 #include <sys/select.h> 70 #endif 71 72 /* Our structures require TAILQ macros, which really every libc should 73 * ship as they are useful beyond belief. 74 * Sadly some libc's don't have sys/queue.h and some that do don't have 75 * the TAILQ_FOREACH macro. For those that don't, the application using 76 * this implementation will need to ship a working queue.h somewhere. 77 * If we don't have sys/queue.h found in config.h, then 78 * allow QUEUE_H to override loading queue.h in the current directory. */ 79 #ifndef TAILQ_FOREACH 80 #ifdef HAVE_SYS_QUEUE_H 81 #include <sys/queue.h> 82 #elif defined(QUEUE_H) 83 #define __QUEUE_HEADER(x) #x 84 #define _QUEUE_HEADER(x) __QUEUE_HEADER(x) 85 #include _QUEUE_HEADER(QUEUE_H) 86 #else 87 #include "queue.h" 88 #endif 89 #endif 90 91 /* 92 * time_t is a signed integer of an unspecified size. 93 * To adjust for time_t wrapping, we need to work the maximum signed 94 * value and use that as a maximum. 95 */ 96 #ifndef TIME_MAX 97 #define TIME_MAX ((1ULL << (sizeof(time_t) * NBBY - 1)) - 1) 98 #endif 99 /* The unsigned maximum is then simple - multiply by two and add one. */ 100 #ifndef UTIME_MAX 101 #define UTIME_MAX (TIME_MAX * 2) + 1 102 #endif 103 104 struct eloop_event { 105 TAILQ_ENTRY(eloop_event) next; 106 int fd; 107 void (*read_cb)(void *); 108 void *read_cb_arg; 109 void (*write_cb)(void *); 110 void *write_cb_arg; 111 struct pollfd *pollfd; 112 }; 113 114 struct eloop_timeout { 115 TAILQ_ENTRY(eloop_timeout) next; 116 unsigned int seconds; 117 unsigned int nseconds; 118 void (*callback)(void *); 119 void *arg; 120 int queue; 121 }; 122 123 struct eloop { 124 TAILQ_HEAD (event_head, eloop_event) events; 125 size_t nevents; 126 struct event_head free_events; 127 128 struct timespec now; 129 TAILQ_HEAD (timeout_head, eloop_timeout) timeouts; 130 struct timeout_head free_timeouts; 131 132 void (*timeout0)(void *); 133 void *timeout0_arg; 134 const int *signals; 135 size_t signals_len; 136 void (*signal_cb)(int, void *); 137 void *signal_cb_ctx; 138 139 struct pollfd *fds; 140 size_t nfds; 141 142 int exitnow; 143 int exitcode; 144 }; 145 146 #ifdef HAVE_REALLOCARRAY 147 #define eloop_realloca reallocarray 148 #else 149 /* Handy routing to check for potential overflow. 150 * reallocarray(3) and reallocarr(3) are not portable. */ 151 #define SQRT_SIZE_MAX (((size_t)1) << (sizeof(size_t) * CHAR_BIT / 2)) 152 static void * 153 eloop_realloca(void *ptr, size_t n, size_t size) 154 { 155 156 if ((n | size) >= SQRT_SIZE_MAX && n > SIZE_MAX / size) { 157 errno = EOVERFLOW; 158 return NULL; 159 } 160 return realloc(ptr, n * size); 161 } 162 #endif 163 164 #ifdef HAVE_PSELECT 165 /* Wrapper around pselect, to imitate the ppoll call. */ 166 static int 167 eloop_ppoll(struct pollfd * fds, nfds_t nfds, 168 const struct timespec *ts, const sigset_t *sigmask) 169 { 170 fd_set read_fds, write_fds; 171 nfds_t n; 172 int maxfd, r; 173 174 FD_ZERO(&read_fds); 175 FD_ZERO(&write_fds); 176 maxfd = 0; 177 for (n = 0; n < nfds; n++) { 178 if (fds[n].events & POLLIN) { 179 FD_SET(fds[n].fd, &read_fds); 180 if (fds[n].fd > maxfd) 181 maxfd = fds[n].fd; 182 } 183 if (fds[n].events & POLLOUT) { 184 FD_SET(fds[n].fd, &write_fds); 185 if (fds[n].fd > maxfd) 186 maxfd = fds[n].fd; 187 } 188 } 189 190 r = pselect(maxfd + 1, &read_fds, &write_fds, NULL, ts, sigmask); 191 if (r > 0) { 192 for (n = 0; n < nfds; n++) { 193 fds[n].revents = 194 FD_ISSET(fds[n].fd, &read_fds) ? POLLIN : 0; 195 if (FD_ISSET(fds[n].fd, &write_fds)) 196 fds[n].revents |= POLLOUT; 197 } 198 } 199 200 return r; 201 } 202 #endif 203 204 unsigned long long 205 eloop_timespec_diff(const struct timespec *tsp, const struct timespec *usp, 206 unsigned int *nsp) 207 { 208 unsigned long long tsecs, usecs, secs; 209 long nsecs; 210 211 if (tsp->tv_sec < 0) /* time wreapped */ 212 tsecs = UTIME_MAX - (unsigned long long)(-tsp->tv_sec); 213 else 214 tsecs = (unsigned long long)tsp->tv_sec; 215 if (usp->tv_sec < 0) /* time wrapped */ 216 usecs = UTIME_MAX - (unsigned long long)(-usp->tv_sec); 217 else 218 usecs = (unsigned long long)usp->tv_sec; 219 220 if (usecs > tsecs) /* time wrapped */ 221 secs = (UTIME_MAX - usecs) + tsecs; 222 else 223 secs = tsecs - usecs; 224 225 nsecs = tsp->tv_nsec - usp->tv_nsec; 226 if (nsecs < 0) { 227 if (secs == 0) 228 nsecs = 0; 229 else { 230 secs--; 231 nsecs += NSEC_PER_SEC; 232 } 233 } 234 if (nsp != NULL) 235 *nsp = (unsigned int)nsecs; 236 return secs; 237 } 238 239 static void 240 eloop_reduce_timers(struct eloop *eloop) 241 { 242 struct timespec now; 243 unsigned long long secs; 244 unsigned int nsecs; 245 struct eloop_timeout *t; 246 247 clock_gettime(CLOCK_MONOTONIC, &now); 248 secs = eloop_timespec_diff(&now, &eloop->now, &nsecs); 249 250 TAILQ_FOREACH(t, &eloop->timeouts, next) { 251 if (secs > t->seconds) { 252 t->seconds = 0; 253 t->nseconds = 0; 254 } else { 255 t->seconds -= (unsigned int)secs; 256 if (nsecs > t->nseconds) { 257 if (t->seconds == 0) 258 t->nseconds = 0; 259 else { 260 t->seconds--; 261 t->nseconds = NSEC_PER_SEC 262 - (nsecs - t->nseconds); 263 } 264 } else 265 t->nseconds -= nsecs; 266 } 267 } 268 269 eloop->now = now; 270 } 271 272 static void 273 eloop_event_setup_fds(struct eloop *eloop) 274 { 275 struct eloop_event *e; 276 struct pollfd *pfd; 277 278 pfd = eloop->fds; 279 TAILQ_FOREACH(e, &eloop->events, next) { 280 e->pollfd = pfd; 281 pfd->fd = e->fd; 282 pfd->events = 0; 283 if (e->read_cb != NULL) 284 pfd->events |= POLLIN; 285 if (e->write_cb != NULL) 286 pfd->events |= POLLOUT; 287 pfd->revents = 0; 288 pfd++; 289 } 290 } 291 292 int 293 eloop_event_add_rw(struct eloop *eloop, int fd, 294 void (*read_cb)(void *), void *read_cb_arg, 295 void (*write_cb)(void *), void *write_cb_arg) 296 { 297 struct eloop_event *e; 298 struct pollfd *pfd; 299 300 assert(eloop != NULL); 301 assert(read_cb != NULL || write_cb != NULL); 302 if (fd == -1) { 303 errno = EINVAL; 304 return -1; 305 } 306 307 TAILQ_FOREACH(e, &eloop->events, next) { 308 if (e->fd == fd) 309 break; 310 } 311 312 if (e == NULL) { 313 if (eloop->nevents + 1 > eloop->nfds) { 314 pfd = eloop_realloca(eloop->fds, eloop->nevents + 1, 315 sizeof(*pfd)); 316 if (pfd == NULL) 317 return -1; 318 eloop->fds = pfd; 319 eloop->nfds++; 320 } 321 322 e = TAILQ_FIRST(&eloop->free_events); 323 if (e != NULL) 324 TAILQ_REMOVE(&eloop->free_events, e, next); 325 else { 326 e = malloc(sizeof(*e)); 327 if (e == NULL) 328 return -1; 329 TAILQ_INSERT_HEAD(&eloop->events, e, next); 330 } 331 e->fd = fd; 332 eloop->nevents++; 333 } 334 335 e->read_cb = read_cb; 336 e->read_cb_arg = read_cb_arg; 337 e->write_cb = write_cb; 338 e->write_cb_arg = write_cb_arg; 339 340 eloop_event_setup_fds(eloop); 341 return 0; 342 } 343 344 int 345 eloop_event_add(struct eloop *eloop, int fd, 346 void (*read_cb)(void *), void *read_cb_arg) 347 { 348 349 return eloop_event_add_rw(eloop, fd, read_cb, read_cb_arg, NULL, NULL); 350 } 351 352 int 353 eloop_event_add_w(struct eloop *eloop, int fd, 354 void (*write_cb)(void *), void *write_cb_arg) 355 { 356 357 return eloop_event_add_rw(eloop, fd, NULL,NULL, write_cb, write_cb_arg); 358 } 359 360 int 361 eloop_event_delete_write(struct eloop *eloop, int fd, int write_only) 362 { 363 struct eloop_event *e; 364 365 assert(eloop != NULL); 366 367 TAILQ_FOREACH(e, &eloop->events, next) { 368 if (e->fd == fd) 369 break; 370 } 371 if (e == NULL) { 372 errno = ENOENT; 373 return -1; 374 } 375 376 if (write_only) { 377 if (e->write_cb == NULL) 378 return 0; 379 if (e->read_cb == NULL) 380 goto remove; 381 e->write_cb = NULL; 382 e->write_cb_arg = NULL; 383 goto done; 384 } 385 386 remove: 387 TAILQ_REMOVE(&eloop->events, e, next); 388 TAILQ_INSERT_TAIL(&eloop->free_events, e, next); 389 eloop->nevents--; 390 391 done: 392 eloop_event_setup_fds(eloop); 393 return 1; 394 } 395 396 /* 397 * This implementation should cope with UINT_MAX seconds on a system 398 * where time_t is INT32_MAX. It should also cope with the monotonic timer 399 * wrapping, although this is highly unlikely. 400 * unsigned int should match or be greater than any on wire specified timeout. 401 */ 402 static int 403 eloop_q_timeout_add(struct eloop *eloop, int queue, 404 unsigned int seconds, unsigned int nseconds, 405 void (*callback)(void *), void *arg) 406 { 407 struct eloop_timeout *t, *tt = NULL; 408 409 assert(eloop != NULL); 410 assert(callback != NULL); 411 assert(nseconds <= NSEC_PER_SEC); 412 413 /* Remove existing timeout if present. */ 414 TAILQ_FOREACH(t, &eloop->timeouts, next) { 415 if (t->callback == callback && t->arg == arg) { 416 TAILQ_REMOVE(&eloop->timeouts, t, next); 417 break; 418 } 419 } 420 421 if (t == NULL) { 422 /* No existing, so allocate or grab one from the free pool. */ 423 if ((t = TAILQ_FIRST(&eloop->free_timeouts))) { 424 TAILQ_REMOVE(&eloop->free_timeouts, t, next); 425 } else { 426 if ((t = malloc(sizeof(*t))) == NULL) 427 return -1; 428 } 429 } 430 431 eloop_reduce_timers(eloop); 432 433 t->seconds = seconds; 434 t->nseconds = nseconds; 435 t->callback = callback; 436 t->arg = arg; 437 t->queue = queue; 438 439 /* The timeout list should be in chronological order, 440 * soonest first. */ 441 TAILQ_FOREACH(tt, &eloop->timeouts, next) { 442 if (t->seconds < tt->seconds || 443 (t->seconds == tt->seconds && t->nseconds < tt->nseconds)) 444 { 445 TAILQ_INSERT_BEFORE(tt, t, next); 446 return 0; 447 } 448 } 449 TAILQ_INSERT_TAIL(&eloop->timeouts, t, next); 450 return 0; 451 } 452 453 int 454 eloop_q_timeout_add_tv(struct eloop *eloop, int queue, 455 const struct timespec *when, void (*callback)(void *), void *arg) 456 { 457 458 if (when->tv_sec < 0 || (unsigned long)when->tv_sec > UINT_MAX) { 459 errno = EINVAL; 460 return -1; 461 } 462 if (when->tv_nsec < 0 || when->tv_nsec > NSEC_PER_SEC) { 463 errno = EINVAL; 464 return -1; 465 } 466 467 return eloop_q_timeout_add(eloop, queue, 468 (unsigned int)when->tv_sec, (unsigned int)when->tv_sec, 469 callback, arg); 470 } 471 472 int 473 eloop_q_timeout_add_sec(struct eloop *eloop, int queue, unsigned int seconds, 474 void (*callback)(void *), void *arg) 475 { 476 477 return eloop_q_timeout_add(eloop, queue, seconds, 0, callback, arg); 478 } 479 480 int 481 eloop_q_timeout_add_msec(struct eloop *eloop, int queue, unsigned long when, 482 void (*callback)(void *), void *arg) 483 { 484 unsigned long seconds, nseconds; 485 486 seconds = when / MSEC_PER_SEC; 487 if (seconds > UINT_MAX) { 488 errno = EINVAL; 489 return -1; 490 } 491 492 nseconds = (when % MSEC_PER_SEC) * NSEC_PER_MSEC; 493 return eloop_q_timeout_add(eloop, queue, 494 (unsigned int)seconds, (unsigned int)nseconds, callback, arg); 495 } 496 497 static int 498 eloop_timeout_add_now(struct eloop *eloop, 499 void (*callback)(void *), void *arg) 500 { 501 502 assert(eloop->timeout0 == NULL); 503 eloop->timeout0 = callback; 504 eloop->timeout0_arg = arg; 505 return 0; 506 } 507 508 int 509 eloop_q_timeout_delete(struct eloop *eloop, int queue, 510 void (*callback)(void *), void *arg) 511 { 512 struct eloop_timeout *t, *tt; 513 int n; 514 515 assert(eloop != NULL); 516 517 n = 0; 518 TAILQ_FOREACH_SAFE(t, &eloop->timeouts, next, tt) { 519 if ((queue == 0 || t->queue == queue) && 520 t->arg == arg && 521 (!callback || t->callback == callback)) 522 { 523 TAILQ_REMOVE(&eloop->timeouts, t, next); 524 TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next); 525 n++; 526 } 527 } 528 return n; 529 } 530 531 void 532 eloop_exit(struct eloop *eloop, int code) 533 { 534 535 assert(eloop != NULL); 536 537 eloop->exitcode = code; 538 eloop->exitnow = 1; 539 } 540 541 void 542 eloop_enter(struct eloop *eloop) 543 { 544 545 eloop->exitnow = 0; 546 } 547 548 void 549 eloop_signal_set_cb(struct eloop *eloop, 550 const int *signals, size_t signals_len, 551 void (*signal_cb)(int, void *), void *signal_cb_ctx) 552 { 553 554 assert(eloop != NULL); 555 556 eloop->signals = signals; 557 eloop->signals_len = signals_len; 558 eloop->signal_cb = signal_cb; 559 eloop->signal_cb_ctx = signal_cb_ctx; 560 } 561 562 struct eloop_siginfo { 563 int sig; 564 struct eloop *eloop; 565 }; 566 static struct eloop_siginfo _eloop_siginfo; 567 static struct eloop *_eloop; 568 569 static void 570 eloop_signal1(void *arg) 571 { 572 struct eloop_siginfo *si = arg; 573 574 si->eloop->signal_cb(si->sig, si->eloop->signal_cb_ctx); 575 } 576 577 static void 578 eloop_signal3(int sig, __unused siginfo_t *siginfo, __unused void *arg) 579 { 580 581 /* So that we can operate safely under a signal we instruct 582 * eloop to pass a copy of the siginfo structure to handle_signal1 583 * as the very first thing to do. */ 584 _eloop_siginfo.eloop = _eloop; 585 _eloop_siginfo.sig = sig; 586 eloop_timeout_add_now(_eloop_siginfo.eloop, 587 eloop_signal1, &_eloop_siginfo); 588 } 589 590 int 591 eloop_signal_mask(struct eloop *eloop, sigset_t *oldset) 592 { 593 sigset_t newset; 594 size_t i; 595 struct sigaction sa = { 596 .sa_sigaction = eloop_signal3, 597 .sa_flags = SA_SIGINFO, 598 }; 599 600 assert(eloop != NULL); 601 602 sigemptyset(&newset); 603 for (i = 0; i < eloop->signals_len; i++) 604 sigaddset(&newset, eloop->signals[i]); 605 if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1) 606 return -1; 607 608 _eloop = eloop; 609 sigemptyset(&sa.sa_mask); 610 611 for (i = 0; i < eloop->signals_len; i++) { 612 if (sigaction(eloop->signals[i], &sa, NULL) == -1) 613 return -1; 614 } 615 return 0; 616 } 617 618 struct eloop * 619 eloop_new(void) 620 { 621 struct eloop *eloop; 622 623 eloop = calloc(1, sizeof(*eloop)); 624 if (eloop == NULL) 625 return NULL; 626 627 /* Check we have a working monotonic clock. */ 628 if (clock_gettime(CLOCK_MONOTONIC, &eloop->now) == -1) { 629 free(eloop); 630 return NULL; 631 } 632 633 TAILQ_INIT(&eloop->events); 634 TAILQ_INIT(&eloop->free_events); 635 TAILQ_INIT(&eloop->timeouts); 636 TAILQ_INIT(&eloop->free_timeouts); 637 eloop->exitcode = EXIT_FAILURE; 638 639 return eloop; 640 } 641 642 void 643 eloop_clear(struct eloop *eloop) 644 { 645 struct eloop_event *e; 646 struct eloop_timeout *t; 647 648 if (eloop == NULL) 649 return; 650 651 eloop->nevents = 0; 652 eloop->signals = NULL; 653 eloop->signals_len = 0; 654 655 while ((e = TAILQ_FIRST(&eloop->events))) { 656 TAILQ_REMOVE(&eloop->events, e, next); 657 free(e); 658 } 659 while ((e = TAILQ_FIRST(&eloop->free_events))) { 660 TAILQ_REMOVE(&eloop->free_events, e, next); 661 free(e); 662 } 663 while ((t = TAILQ_FIRST(&eloop->timeouts))) { 664 TAILQ_REMOVE(&eloop->timeouts, t, next); 665 free(t); 666 } 667 while ((t = TAILQ_FIRST(&eloop->free_timeouts))) { 668 TAILQ_REMOVE(&eloop->free_timeouts, t, next); 669 free(t); 670 } 671 672 free(eloop->fds); 673 eloop->fds = NULL; 674 eloop->nfds = 0; 675 } 676 677 void 678 eloop_free(struct eloop *eloop) 679 { 680 681 eloop_clear(eloop); 682 free(eloop); 683 } 684 685 int 686 eloop_start(struct eloop *eloop, sigset_t *signals) 687 { 688 int n; 689 struct eloop_event *e; 690 struct eloop_timeout *t; 691 void (*t0)(void *); 692 struct timespec ts, *tsp; 693 694 assert(eloop != NULL); 695 696 for (;;) { 697 if (eloop->exitnow) 698 break; 699 700 /* Run all timeouts first. */ 701 if (eloop->timeout0) { 702 t0 = eloop->timeout0; 703 eloop->timeout0 = NULL; 704 t0(eloop->timeout0_arg); 705 continue; 706 } 707 708 t = TAILQ_FIRST(&eloop->timeouts); 709 if (t == NULL && eloop->nevents == 0) 710 break; 711 712 if (t != NULL) 713 eloop_reduce_timers(eloop); 714 715 if (t != NULL && t->seconds == 0 && t->nseconds == 0) { 716 TAILQ_REMOVE(&eloop->timeouts, t, next); 717 t->callback(t->arg); 718 TAILQ_INSERT_TAIL(&eloop->free_timeouts, t, next); 719 continue; 720 } 721 722 if (t != NULL) { 723 if (t->seconds > INT_MAX) { 724 ts.tv_sec = (time_t)INT_MAX; 725 ts.tv_nsec = 0; 726 } else { 727 ts.tv_sec = (time_t)t->seconds; 728 ts.tv_nsec = (long)t->nseconds; 729 } 730 tsp = &ts; 731 } else 732 tsp = NULL; 733 734 n = ppoll(eloop->fds, (nfds_t)eloop->nevents, tsp, signals); 735 if (n == -1) { 736 if (errno == EINTR) 737 continue; 738 return -errno; 739 } 740 if (n == 0) 741 continue; 742 743 TAILQ_FOREACH(e, &eloop->events, next) { 744 if (e->pollfd->revents & POLLOUT) { 745 if (e->write_cb != NULL) { 746 e->write_cb(e->write_cb_arg); 747 break; 748 } 749 } 750 if (e->pollfd->revents) { 751 if (e->read_cb != NULL) { 752 e->read_cb(e->read_cb_arg); 753 break; 754 } 755 } 756 } 757 } 758 759 return eloop->exitcode; 760 } 761