select.c (18566B)
1 /* select.c 2 * Select Loop 3 * (c) 2002 Mikulas Patocka 4 * This file is a part of the Links program, released under GPL. 5 */ 6 7 #include <limits.h> 8 9 #include "links.h" 10 11 #if defined(evtimer_set) && !defined(timeout_set) 12 #define timeout_set evtimer_set 13 #endif 14 #if defined(evtimer_add) && !defined(timeout_add) 15 #define timeout_add evtimer_add 16 #endif 17 #if defined(evtimer_del) && !defined(timeout_del) 18 #define timeout_del evtimer_del 19 #endif 20 21 struct thread { 22 void (*read_func)(void *); 23 void (*write_func)(void *); 24 void *data; 25 struct event *read_event; 26 struct event *write_event; 27 }; 28 29 static struct thread *threads = NULL; 30 static int n_threads = 0; 31 32 static fd_set w_read; 33 static fd_set w_write; 34 35 static fd_set x_read; 36 static fd_set x_write; 37 38 static int w_max; 39 40 struct timer { 41 list_entry_1st; 42 uttime interval; 43 void (*func)(void *); 44 void *data; 45 }; 46 47 static struct list_head timers = { &timers, &timers }; 48 49 void 50 portable_sleep(unsigned msec) 51 { 52 struct timeval tv; 53 int rs; 54 block_signals(0, 0); 55 tv.tv_sec = msec / 1000; 56 tv.tv_usec = msec % 1000 * 1000; 57 EINTRLOOP(rs, select(0, NULL, NULL, NULL, &tv)); 58 unblock_signals(); 59 } 60 61 static int 62 can_do_io(int fd, int wr, int sec) 63 { 64 fd_set fds; 65 struct timeval tv, *tvp; 66 int rs; 67 68 if (fd < 0) 69 die("can_do_io: handle %d", fd); 70 71 struct pollfd p; 72 p.fd = fd; 73 p.events = !wr ? POLLIN : POLLOUT; 74 EINTRLOOP(rs, poll(&p, 1, sec < 0 ? -1 : sec * 1000)); 75 if (rs < 0) 76 die("poll for %s (%d) failed: %s", !wr ? "read" : "write", fd, 77 strerror(errno)); 78 if (!rs) 79 return 0; 80 if (p.revents & POLLNVAL) 81 goto fallback; 82 return 1; 83 fallback: 84 if (sec >= 0) { 85 tv.tv_sec = sec; 86 tv.tv_usec = 0; 87 tvp = &tv; 88 } else 89 tvp = NULL; 90 FD_ZERO(&fds); 91 if (fd >= (int)FD_SETSIZE) 92 die("too big handle %d\n", fd); 93 FD_SET(fd, &fds); 94 if (!wr) 95 EINTRLOOP(rs, select(fd + 1, &fds, NULL, NULL, tvp)); 96 else 97 EINTRLOOP(rs, select(fd + 1, NULL, &fds, NULL, tvp)); 98 if (rs < 0) 99 die("select for %s (%d) failed: %s\n", !wr ? "read" : "write", 100 fd, strerror(errno)); 101 return rs; 102 } 103 104 int 105 can_write(int fd) 106 { 107 return can_do_io(fd, 1, 0); 108 } 109 110 int 111 can_read_timeout(int fd, int sec) 112 { 113 return can_do_io(fd, 0, sec); 114 } 115 116 int 117 can_read(int fd) 118 { 119 return can_do_io(fd, 0, 0); 120 } 121 122 int 123 close_stderr(void) 124 { 125 int n, h, rs; 126 fflush(stderr); 127 n = c_open(cast_uchar "/dev/null", O_WRONLY | O_NOCTTY); 128 if (n == -1) 129 goto fail1; 130 h = c_dup(2); 131 if (h == -1) 132 goto fail2; 133 EINTRLOOP(rs, dup2(n, 2)); 134 if (rs == -1) 135 goto fail3; 136 EINTRLOOP(rs, close(n)); 137 return h; 138 139 fail3: 140 EINTRLOOP(rs, close(h)); 141 fail2: 142 EINTRLOOP(rs, close(n)); 143 fail1: 144 return -1; 145 } 146 147 void 148 restore_stderr(int h) 149 { 150 int rs; 151 fflush(stderr); 152 if (h == -1) 153 return; 154 EINTRLOOP(rs, dup2(h, 2)); 155 EINTRLOOP(rs, close(h)); 156 } 157 158 unsigned long 159 select_info(int type) 160 { 161 int i, j; 162 switch (type) { 163 case CI_FILES: 164 i = 0; 165 for (j = 0; j < w_max; j++) 166 if (threads[j].read_func || threads[j].write_func) 167 i++; 168 return i; 169 case CI_TIMERS: 170 return list_size(&timers); 171 default: 172 die("select_info_info: bad request\n"); 173 } 174 return 0; 175 } 176 177 struct bottom_half { 178 list_entry_1st; 179 void (*fn)(void *); 180 void *data; 181 }; 182 183 static struct list_head bottom_halves = { &bottom_halves, &bottom_halves }; 184 185 void 186 register_bottom_half(void (*fn)(void *), void *data) 187 { 188 struct bottom_half *bh = NULL; 189 struct list_head *lbh; 190 foreach (struct bottom_half, bh, lbh, bottom_halves) 191 if (bh->fn == fn && bh->data == data) 192 return; 193 bh = xmalloc(sizeof(struct bottom_half)); 194 bh->fn = fn; 195 bh->data = data; 196 add_to_list(bottom_halves, bh); 197 } 198 199 void 200 unregister_bottom_half(void (*fn)(void *), void *data) 201 { 202 struct bottom_half *bh = NULL; 203 struct list_head *lbh; 204 foreach (struct bottom_half, bh, lbh, bottom_halves) 205 if (bh->fn == fn && bh->data == data) { 206 del_from_list(bh); 207 free(bh); 208 return; 209 } 210 } 211 212 void 213 check_bottom_halves(void) 214 { 215 struct bottom_half *bh; 216 void (*fn)(void *); 217 void *data; 218 rep: 219 if (list_empty(bottom_halves)) 220 return; 221 bh = list_struct(bottom_halves.prev, struct bottom_half); 222 fn = bh->fn; 223 data = bh->data; 224 del_from_list(bh); 225 free(bh); 226 pr(fn(data)){}; 227 goto rep; 228 } 229 230 #define CHK_BH \ 231 if (!list_empty(bottom_halves)) \ 232 check_bottom_halves() 233 234 static void 235 restrict_fds(void) 236 { 237 #if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) 238 #define RLIMIT_NOFILE RLIMIT_OFILE 239 #endif 240 #if defined(RLIMIT_NOFILE) 241 struct rlimit limit; 242 int rs; 243 EINTRLOOP(rs, getrlimit(RLIMIT_NOFILE, &limit)); 244 if (rs) 245 goto skip_limit; 246 if (limit.rlim_cur > FD_SETSIZE) { 247 limit.rlim_cur = FD_SETSIZE; 248 EINTRLOOP(rs, setrlimit(RLIMIT_NOFILE, &limit)); 249 } 250 skip_limit:; 251 #endif 252 } 253 254 unsigned char *sh_file; 255 int sh_line; 256 257 static int event_enabled = 0; 258 259 #ifndef HAVE_EVENT_GET_STRUCT_EVENT_SIZE 260 #define sizeof_struct_event sizeof(struct event) 261 #else 262 #define sizeof_struct_event (event_get_struct_event_size()) 263 #endif 264 265 static inline struct event * 266 timer_event(struct timer *tm) 267 { 268 return (struct event *)((unsigned char *)tm - sizeof_struct_event); 269 } 270 271 static struct event_base *event_base; 272 273 static void 274 event_callback(int h, short ev, void *data) 275 { 276 #ifndef EV_PERSIST 277 if (event_add((struct event *)data, NULL) == -1) 278 die("event_add: %s\n", strerror(errno)); 279 #endif 280 if (!(ev & EV_READ) == !(ev & EV_WRITE)) 281 die("event_callback: invalid flags %d on handle %d\n", (int)ev, 282 h); 283 if (ev & EV_READ) { 284 #if defined(HAVE_LIBEV) 285 /* Old versions of libev badly interact with fork and fire 286 * events spuriously. */ 287 if (ev_version_major() < 4 && !can_read(h)) 288 return; 289 #endif 290 pr(threads[h].read_func(threads[h].data)) 291 { 292 } 293 } else { 294 #if defined(HAVE_LIBEV) 295 /* Old versions of libev badly interact with fork and fire 296 * events spuriously. */ 297 if (ev_version_major() < 4 && !can_write(h)) 298 return; 299 #endif 300 pr(threads[h].write_func(threads[h].data)) 301 { 302 } 303 } 304 CHK_BH; 305 } 306 307 static void 308 timer_callback(int h, short ev, void *data) 309 { 310 struct timer *tm = data; 311 pr(tm->func(tm->data)) 312 { 313 } 314 kill_timer(tm); 315 CHK_BH; 316 } 317 318 static void 319 set_event_for_action(int h, void (*func)(void *), struct event **evptr, 320 short evtype) 321 { 322 if (func) { 323 if (!*evptr) { 324 #ifdef EV_PERSIST 325 evtype |= EV_PERSIST; 326 #endif 327 *evptr = xmalloc(sizeof_struct_event); 328 event_set(*evptr, h, evtype, event_callback, *evptr); 329 if (event_base_set(event_base, *evptr) == -1) 330 die("event_base_set: %s at %s:%d, handle %d\n", 331 strerror(errno), sh_file, sh_line, h); 332 } 333 if (event_add(*evptr, NULL) == -1) 334 die("event_add: %s at %s:%d, handle %d\n", 335 strerror(errno), sh_file, sh_line, h); 336 } else { 337 if (*evptr) { 338 if (event_del(*evptr) == -1) 339 die("event_del: %s at %s:%d, handle %d\n", 340 strerror(errno), sh_file, sh_line, h); 341 } 342 } 343 } 344 345 static void 346 set_events_for_handle(int h) 347 { 348 set_event_for_action(h, threads[h].read_func, &threads[h].read_event, 349 EV_READ); 350 set_event_for_action(h, threads[h].write_func, &threads[h].write_event, 351 EV_WRITE); 352 } 353 354 static void 355 set_event_for_timer(struct timer *tm) 356 { 357 struct timeval tv; 358 struct event *ev = timer_event(tm); 359 timeout_set(ev, timer_callback, tm); 360 if (event_base_set(event_base, ev) == -1) 361 die("event_base_set: %s\n", strerror(errno)); 362 tv.tv_sec = tm->interval / 1000; 363 tv.tv_usec = (tm->interval % 1000) * 1000; 364 #if defined(HAVE_LIBEV) 365 if (!tm->interval && ev_version_major() < 4) { 366 /* libev bug */ 367 tv.tv_usec = 1; 368 } 369 #endif 370 if (timeout_add(ev, &tv) == -1) 371 die("timeout_add: %s\n", strerror(errno)); 372 } 373 374 static void 375 enable_libevent(void) 376 { 377 int i; 378 struct timer *tm = NULL; 379 struct list_head *ltm; 380 381 if (disable_libevent) 382 return; 383 384 event_base = event_base_new(); 385 if (!event_base) 386 return; 387 event_enabled = 1; 388 389 sh_file = (unsigned char *)__FILE__; 390 sh_line = __LINE__; 391 for (i = 0; i < w_max; i++) 392 set_events_for_handle(i); 393 394 foreach (struct timer, tm, ltm, timers) 395 set_event_for_timer(tm); 396 } 397 398 static void 399 terminate_libevent(void) 400 { 401 int i; 402 if (event_enabled) { 403 for (i = 0; i < n_threads; i++) { 404 set_event_for_action(i, NULL, &threads[i].read_event, 405 EV_READ); 406 free(threads[i].read_event); 407 set_event_for_action(i, NULL, &threads[i].write_event, 408 EV_WRITE); 409 free(threads[i].write_event); 410 } 411 event_base_free(event_base); 412 event_enabled = 0; 413 } 414 } 415 416 static void 417 do_event_loop(int flags) 418 { 419 int e; 420 e = event_base_loop(event_base, flags); 421 if (e == -1) 422 die("event_base_loop: %s\n", strerror(errno)); 423 } 424 425 size_t 426 add_event_string(unsigned char **s, size_t l, struct terminal *term) 427 { 428 if (!event_enabled) 429 l = add_to_str( 430 s, l, get_text_translation(TEXT_(T_SELECT_SYSCALL), term)); 431 if (!event_enabled) 432 l = add_to_str(s, l, cast_uchar " ("); 433 #if defined(HAVE_LIBEV) 434 l = add_to_str(s, l, cast_uchar "LibEv"); 435 #else 436 l = add_to_str(s, l, cast_uchar "LibEvent"); 437 #endif 438 l = add_chr_to_str(s, l, ' '); 439 { 440 #if defined(HAVE_LIBEV) 441 /* old libev report bogus version */ 442 if (!casestrcmp(cast_uchar event_get_version(), cast_uchar 443 "EV_VERSION_MAJOR.EV_VERSION_MINOR")) { 444 add_num_to_str(s, &l, ev_version_major()); 445 l = add_chr_to_str(s, *l, '.'); 446 add_num_to_str(s, &l, ev_version_minor()); 447 } else 448 #endif 449 l = add_to_str(s, l, cast_uchar event_get_version()); 450 } 451 if (!event_enabled) { 452 l = add_chr_to_str(s, l, ' '); 453 l = add_to_str(s, l, 454 get_text_translation(TEXT_(T_dISABLED), term)); 455 l = add_chr_to_str(s, l, ')'); 456 } else { 457 l = add_chr_to_str(s, l, ' '); 458 l = add_to_str(s, l, 459 cast_uchar event_base_get_method(event_base)); 460 } 461 return l; 462 } 463 464 static uttime last_time; 465 466 static void 467 check_timers(void) 468 { 469 uttime interval = get_time() - last_time; 470 struct timer *t = NULL; 471 struct list_head *lt; 472 foreach (struct timer, t, lt, timers) { 473 if (t->interval < interval) 474 t->interval = 0; 475 else 476 t->interval -= interval; 477 } 478 while (!list_empty(timers)) { 479 struct timer *t = list_struct(timers.next, struct timer); 480 if (t->interval) 481 break; 482 pr(t->func(t->data)) break; 483 kill_timer(t); 484 CHK_BH; 485 } 486 last_time += interval; 487 } 488 489 struct timer * 490 install_timer(uttime t, void (*func)(void *), void *data) 491 { 492 struct timer *tm; 493 unsigned char *q = xmalloc(sizeof_struct_event + sizeof(struct timer)); 494 tm = (struct timer *)(q + sizeof_struct_event); 495 tm->interval = t; 496 tm->func = func; 497 tm->data = data; 498 if (event_enabled) { 499 set_event_for_timer(tm); 500 add_to_list(timers, tm); 501 } else { 502 struct timer *tt = NULL; 503 struct list_head *ltt; 504 foreach (struct timer, tt, ltt, timers) 505 if (tt->interval >= t) 506 break; 507 add_before_list_entry(ltt, &tm->list_entry); 508 } 509 return tm; 510 } 511 512 void 513 kill_timer(struct timer *tm) 514 { 515 del_from_list(tm); 516 if (event_enabled) 517 timeout_del(timer_event(tm)); 518 free(timer_event(tm)); 519 } 520 521 void (*get_handler(int fd, int tp))(void *) 522 { 523 if (fd < 0) 524 die("get_handler: handle %d\n", fd); 525 if (fd >= w_max) 526 return NULL; 527 switch (tp) { 528 case H_READ: 529 return threads[fd].read_func; 530 case H_WRITE: 531 return threads[fd].write_func; 532 } 533 die("get_handler: bad type %d\n", tp); 534 return NULL; 535 } 536 537 void * 538 get_handler_data(int fd) 539 { 540 if (fd < 0) 541 die("get_handler: handle %d\n", fd); 542 if (fd >= w_max) 543 return NULL; 544 return threads[fd].data; 545 } 546 547 void 548 set_handlers_file_line(int fd, void (*read_func)(void *), 549 void (*write_func)(void *), void *data) 550 { 551 if (fd < 0) 552 goto invl; 553 if (!event_enabled) 554 if (fd >= (int)FD_SETSIZE) { 555 die("too big handle %d at %s:%d\n", fd, sh_file, 556 sh_line); 557 return; 558 } 559 if (fd >= n_threads) { 560 if ((unsigned)fd 561 > (unsigned)INT_MAX / sizeof(struct thread) - 1) 562 overalloc(); 563 threads = xrealloc(threads, (fd + 1) * sizeof(struct thread)); 564 memset(threads + n_threads, 0, 565 (fd + 1 - n_threads) * sizeof(struct thread)); 566 n_threads = fd + 1; 567 } 568 if (threads[fd].read_func == read_func 569 && threads[fd].write_func == write_func && threads[fd].data == data) 570 return; 571 threads[fd].read_func = read_func; 572 threads[fd].write_func = write_func; 573 threads[fd].data = data; 574 if (read_func || write_func) { 575 if (fd >= w_max) 576 w_max = fd + 1; 577 } else if (fd == w_max - 1) { 578 int i; 579 for (i = fd - 1; i >= 0; i--) 580 if (threads[i].read_func || threads[i].write_func) 581 break; 582 w_max = i + 1; 583 } 584 if (event_enabled) { 585 set_events_for_handle(fd); 586 return; 587 } 588 if (read_func) 589 FD_SET(fd, &w_read); 590 else { 591 FD_CLR(fd, &w_read); 592 FD_CLR(fd, &x_read); 593 } 594 if (write_func) 595 FD_SET(fd, &w_write); 596 else { 597 FD_CLR(fd, &w_write); 598 FD_CLR(fd, &x_write); 599 } 600 return; 601 602 invl: 603 die("invalid set_handlers call at %s:%d: %d, %p, %p, %p\n", sh_file, 604 sh_line, fd, read_func, write_func, data); 605 } 606 607 void 608 clear_events(int h, int blocking) 609 { 610 #if !defined(O_NONBLOCK) && !defined(FIONBIO) 611 blocking = 1; 612 #endif 613 while (blocking ? can_read(h) : 1) { 614 unsigned char c[64]; 615 int rd; 616 EINTRLOOP(rd, (int)read(h, c, sizeof c)); 617 if (rd != sizeof c) 618 break; 619 } 620 } 621 622 #if defined(NSIG) && NSIG > 32 623 #define NUM_SIGNALS NSIG 624 #else 625 #define NUM_SIGNALS 32 626 #endif 627 628 static void 629 clear_events_ptr(void *handle) 630 { 631 clear_events((int)(long)handle, 0); 632 } 633 634 struct signal_handler { 635 void (*fn)(void *); 636 void *data; 637 int critical; 638 }; 639 640 static volatile int signal_mask[NUM_SIGNALS]; 641 static volatile struct signal_handler signal_handlers[NUM_SIGNALS]; 642 643 static pid_t signal_pid; 644 int signal_pipe[2]; 645 646 static void 647 got_signal(int sig) 648 { 649 void (*fn)(void *); 650 int sv_errno = errno; 651 /*fprintf(stderr, "ERROR: signal number: %d\n", sig);*/ 652 653 /* if we get signal from a forked child, don't do anything */ 654 if (getpid() != signal_pid) 655 goto ret; 656 657 if (sig >= NUM_SIGNALS || sig < 0) 658 goto ret; 659 fn = signal_handlers[sig].fn; 660 if (!fn) 661 goto ret; 662 if (signal_handlers[sig].critical) { 663 fn(signal_handlers[sig].data); 664 goto ret; 665 } 666 signal_mask[sig] = 1; 667 if (can_write(signal_pipe[1])) { 668 int wr; 669 EINTRLOOP(wr, (int)write(signal_pipe[1], "", 1)); 670 } 671 ret: 672 errno = sv_errno; 673 } 674 675 static struct sigaction sa_zero; 676 677 void 678 install_signal_handler(int sig, void (*fn)(void *), void *data, int critical) 679 { 680 int rs; 681 struct sigaction sa = sa_zero; 682 if (sig >= NUM_SIGNALS || sig < 0) { 683 die("bad signal number: %d\n", sig); 684 return; 685 } 686 if (!fn) 687 sa.sa_handler = SIG_IGN; 688 else 689 sa.sa_handler = (void (*)(int))got_signal; 690 sigfillset(&sa.sa_mask); 691 sa.sa_flags = SA_RESTART; 692 if (!fn) 693 EINTRLOOP(rs, sigaction(sig, &sa, NULL)); 694 signal_handlers[sig].fn = fn; 695 signal_handlers[sig].data = data; 696 signal_handlers[sig].critical = critical; 697 if (fn) 698 EINTRLOOP(rs, sigaction(sig, &sa, NULL)); 699 } 700 701 void 702 interruptible_signal(int sig, int in) 703 { 704 struct sigaction sa = sa_zero; 705 int rs; 706 if (sig >= NUM_SIGNALS || sig < 0) { 707 die("bad signal number: %d\n", sig); 708 return; 709 } 710 if (!signal_handlers[sig].fn) 711 return; 712 sa.sa_handler = (void (*)(int))got_signal; 713 sigfillset(&sa.sa_mask); 714 if (!in) 715 sa.sa_flags = SA_RESTART; 716 EINTRLOOP(rs, sigaction(sig, &sa, NULL)); 717 } 718 719 static sigset_t sig_old_mask; 720 static int sig_unblock = 0; 721 722 void 723 block_signals(int except1, int except2) 724 { 725 int rs; 726 sigset_t mask; 727 sigfillset(&mask); 728 if (except1) 729 sigdelset(&mask, except1); 730 if (except2) 731 sigdelset(&mask, except2); 732 #ifdef SIGILL 733 sigdelset(&mask, SIGILL); 734 #endif 735 #ifdef SIGABRT 736 sigdelset(&mask, SIGABRT); 737 #endif 738 #ifdef SIGFPE 739 sigdelset(&mask, SIGFPE); 740 #endif 741 #ifdef SIGSEGV 742 sigdelset(&mask, SIGSEGV); 743 #endif 744 #ifdef SIGBUS 745 sigdelset(&mask, SIGBUS); 746 #endif 747 EINTRLOOP(rs, sigprocmask(SIG_BLOCK, &mask, &sig_old_mask)); 748 if (!rs) 749 sig_unblock = 1; 750 } 751 752 void 753 unblock_signals(void) 754 { 755 int rs; 756 if (sig_unblock) { 757 EINTRLOOP(rs, sigprocmask(SIG_SETMASK, &sig_old_mask, NULL)); 758 sig_unblock = 0; 759 } 760 } 761 762 static int 763 check_signals(void) 764 { 765 int r = 0; 766 int i; 767 for (i = 0; i < NUM_SIGNALS; i++) 768 if (signal_mask[i]) { 769 signal_mask[i] = 0; 770 if (signal_handlers[i].fn) { 771 pr(signal_handlers[i].fn( 772 signal_handlers[i].data)) 773 { 774 } 775 } 776 CHK_BH; 777 r = 1; 778 } 779 return r; 780 } 781 782 #ifdef SIGCHLD 783 static void 784 sigchld(void *p) 785 { 786 pid_t pid; 787 #ifndef WNOHANG 788 EINTRLOOP(pid, wait(NULL)); 789 #else 790 do { 791 EINTRLOOP(pid, waitpid(-1, NULL, WNOHANG)); 792 } while (pid > 0); 793 #endif 794 } 795 796 void 797 set_sigcld(void) 798 { 799 install_signal_handler(SIGCHLD, sigchld, NULL, 1); 800 } 801 #else 802 void 803 set_sigcld(void) 804 { 805 } 806 #endif 807 808 void 809 reinit_child(void) 810 { 811 signal_pid = getpid(); 812 if (event_enabled) { 813 if (event_reinit(event_base)) 814 die("event_reinit: %s\n", strerror(errno)); 815 } 816 } 817 818 int terminate_loop = 0; 819 820 void 821 select_loop(void (*init)(void)) 822 { 823 824 memset(&sa_zero, 0, sizeof sa_zero); 825 memset((void *)signal_mask, 0, sizeof signal_mask); 826 memset((void *)signal_handlers, 0, sizeof signal_handlers); 827 FD_ZERO(&w_read); 828 FD_ZERO(&w_write); 829 w_max = 0; 830 last_time = get_time(); 831 ignore_signals(); 832 signal_pid = getpid(); 833 if (c_pipe(signal_pipe)) 834 die("can't create pipe for signal handling\n"); 835 set_nonblock(signal_pipe[0]); 836 set_nonblock(signal_pipe[1]); 837 set_handlers(signal_pipe[0], clear_events_ptr, NULL, 838 (void *)(long)signal_pipe[0]); 839 init(); 840 CHK_BH; 841 enable_libevent(); 842 if (!event_enabled) { 843 restrict_fds(); 844 } 845 if (event_enabled) { 846 while (!terminate_loop) { 847 check_signals(); 848 do_event_loop(EVLOOP_NONBLOCK); 849 check_signals(); 850 redraw_all_terminals(); 851 if (terminate_loop) 852 break; 853 do_event_loop(EVLOOP_ONCE); 854 } 855 } else 856 857 while (!terminate_loop) { 858 volatile int n; /* volatile because of setjmp */ 859 int i; 860 struct timeval tv; 861 struct timeval *tm = NULL; 862 check_signals(); 863 check_timers(); 864 redraw_all_terminals(); 865 if (!list_empty(timers)) { 866 uttime tt = 867 list_struct(timers.next, struct timer) 868 ->interval 869 + 1; 870 tv.tv_sec = tt / 1000 < INT_MAX 871 ? (int)(tt / 1000) 872 : INT_MAX; 873 tv.tv_usec = (tt % 1000) * 1000; 874 tm = &tv; 875 } 876 memcpy(&x_read, &w_read, sizeof(fd_set)); 877 memcpy(&x_write, &w_write, sizeof(fd_set)); 878 if (terminate_loop) 879 break; 880 if ((n = select(w_max, &x_read, &x_write, NULL, tm)) 881 < 0) { 882 if (errno != EINTR) 883 die("select: %s\n", strerror(errno)); 884 continue; 885 } 886 check_signals(); 887 check_timers(); 888 i = -1; 889 while (n > 0 && ++i < w_max) { 890 int k = 0; 891 if (FD_ISSET(i, &x_read)) { 892 if (threads[i].read_func) { 893 pr(threads[i].read_func( 894 threads[i].data)) continue; 895 CHK_BH; 896 } 897 k = 1; 898 } 899 if (FD_ISSET(i, &x_write)) { 900 if (threads[i].write_func) { 901 pr(threads[i].write_func( 902 threads[i].data)) continue; 903 CHK_BH; 904 } 905 k = 1; 906 } 907 n -= k; 908 } 909 } 910 } 911 912 void 913 terminate_select(void) 914 { 915 terminate_libevent(); 916 free(threads); 917 }