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 "links.h"
8
9 /*
10 #define DEBUG_CALLS
11 */
12
13 #ifdef USE_LIBEVENT
14 #if defined(evtimer_set) && !defined(timeout_set)
15 #define timeout_set evtimer_set
16 #endif
17 #if defined(evtimer_add) && !defined(timeout_add)
18 #define timeout_add evtimer_add
19 #endif
20 #if defined(evtimer_del) && !defined(timeout_del)
21 #define timeout_del evtimer_del
22 #endif
23 #endif
24
25 struct thread {
26 void (*read_func)(void *);
27 void (*write_func)(void *);
28 void *data;
29 #ifdef USE_LIBEVENT
30 struct event *read_event;
31 struct event *write_event;
32 #endif
33 };
34
35 static struct thread *threads = DUMMY;
36 static int n_threads = 0;
37
38 static fd_set w_read;
39 static fd_set w_write;
40
41 static fd_set x_read;
42 static fd_set x_write;
43
44 static int w_max;
45
46 struct timer {
47 list_entry_1st
48 uttime interval;
49 void (*func)(void *);
50 void *data;
51 list_entry_last
52 };
53
54 static struct list_head timers = { &timers, &timers };
55
56
57 #if !defined(OS2) && !defined(OPENVMS)
portable_sleep(unsigned msec)58 void portable_sleep(unsigned msec)
59 {
60 struct timeval tv;
61 int rs;
62 block_signals(0, 0);
63 tv.tv_sec = msec / 1000;
64 tv.tv_usec = msec % 1000 * 1000;
65 EINTRLOOP(rs, select(0, NULL, NULL, NULL, &tv));
66 unblock_signals();
67 }
68 #endif
69
can_do_io(int fd,int wr,int sec)70 static int can_do_io(int fd, int wr, int sec)
71 {
72 fd_set fds;
73 struct timeval tv, *tvp;
74 int rs;
75
76 if (fd < 0)
77 internal_error("can_do_io: handle %d", fd);
78
79 #if defined(USE_POLL)
80 {
81 struct pollfd p;
82 p.fd = fd;
83 p.events = !wr ? POLLIN : POLLOUT;
84 EINTRLOOP(rs, poll(&p, 1, sec < 0 ? -1 : sec * 1000));
85 if (rs < 0) fatal_exit("ERROR: poll for %s (%d) failed: %s", !wr ? "read" : "write", fd, strerror(errno));
86 if (!rs) return 0;
87 if (p.revents & POLLNVAL) goto fallback;
88 return 1;
89 }
90 fallback:
91 #endif
92 if (sec >= 0) {
93 tv.tv_sec = sec;
94 tv.tv_usec = 0;
95 tvp = &tv;
96 } else {
97 tvp = NULL;
98 }
99 FD_ZERO(&fds);
100 if (fd >= (int)FD_SETSIZE) {
101 fatal_exit("too big handle %d", fd);
102 }
103 FD_SET(fd, &fds);
104 if (!wr)
105 EINTRLOOP(rs, select(fd + 1, &fds, NULL, NULL, tvp));
106 else
107 EINTRLOOP(rs, select(fd + 1, NULL, &fds, NULL, tvp));
108 if (rs < 0) fatal_exit("ERROR: select for %s (%d) failed: %s", !wr ? "read" : "write", fd, strerror(errno));
109 return rs;
110 }
111
can_write(int fd)112 int can_write(int fd)
113 {
114 return can_do_io(fd, 1, 0);
115 }
116
can_read_timeout(int fd,int sec)117 int can_read_timeout(int fd, int sec)
118 {
119 return can_do_io(fd, 0, sec);
120 }
121
can_read(int fd)122 int can_read(int fd)
123 {
124 return can_do_io(fd, 0, 0);
125 }
126
127
close_std_handle(int std)128 int close_std_handle(int std)
129 {
130 #ifndef DOS
131 int n, h, rs;
132 if (std == 1)
133 fflush(stdout);
134 if (std == 2)
135 fflush(stderr);
136 n = c_open(cast_uchar "/dev/null", O_WRONLY | O_NOCTTY);
137 if (n == -1)
138 goto fail1;
139 h = c_dup(std);
140 if (h == -1)
141 goto fail2;
142 EINTRLOOP(rs, dup2(n, std));
143 if (rs == -1)
144 goto fail3;
145 EINTRLOOP(rs, close(n));
146 return h;
147
148 fail3:
149 EINTRLOOP(rs, close(h));
150 fail2:
151 EINTRLOOP(rs, close(n));
152 fail1:
153 #endif
154 return -1;
155 }
156
restore_std_handle(int std,int h)157 void restore_std_handle(int std, int h)
158 {
159 #ifndef DOS
160 int rs;
161 if (std == 1)
162 fflush(stdout);
163 if (std == 2)
164 fflush(stderr);
165 if (h == -1)
166 return;
167 EINTRLOOP(rs, dup2(h, std));
168 EINTRLOOP(rs, close(h));
169 #endif
170 }
171
172
select_info(int type)173 unsigned long select_info(int type)
174 {
175 int i, j;
176 switch (type) {
177 case CI_FILES:
178 i = 0;
179 for (j = 0; j < w_max; j++)
180 if (threads[j].read_func || threads[j].write_func) i++;
181 return i;
182 case CI_TIMERS:
183 return list_size(&timers);
184 default:
185 internal_error("select_info_info: bad request");
186 }
187 return 0;
188 }
189
190 struct bottom_half {
191 list_entry_1st
192 void (*fn)(void *);
193 void *data;
194 list_entry_last
195 };
196
197 static struct list_head bottom_halves = { &bottom_halves, &bottom_halves };
198
register_bottom_half(void (* fn)(void *),void * data)199 void register_bottom_half(void (*fn)(void *), void *data)
200 {
201 struct bottom_half *bh;
202 struct list_head *lbh;
203 foreach(struct bottom_half, bh, lbh, bottom_halves) if (bh->fn == fn && bh->data == data) return;
204 bh = mem_alloc(sizeof(struct bottom_half));
205 bh->fn = fn;
206 bh->data = data;
207 add_to_list(bottom_halves, bh);
208 }
209
unregister_bottom_half(void (* fn)(void *),void * data)210 void unregister_bottom_half(void (*fn)(void *), void *data)
211 {
212 struct bottom_half *bh;
213 struct list_head *lbh;
214 foreach(struct bottom_half, bh, lbh, bottom_halves) if (bh->fn == fn && bh->data == data) {
215 del_from_list(bh);
216 mem_free(bh);
217 return;
218 }
219 }
220
check_bottom_halves(void)221 void check_bottom_halves(void)
222 {
223 struct bottom_half *bh;
224 void (*fn)(void *);
225 void *data;
226 rep:
227 if (list_empty(bottom_halves)) return;
228 bh = list_struct(bottom_halves.prev, struct bottom_half);
229 fn = bh->fn;
230 data = bh->data;
231 del_from_list(bh);
232 mem_free(bh);
233 #ifdef DEBUG_CALLS
234 fprintf(stderr, "call: bh %p\n", fn);
235 #endif
236 pr(fn(data)) {
237 #ifdef OOPS
238 free_list(struct bottom_half, bottom_halves);
239 return;
240 #endif
241 };
242 #ifdef DEBUG_CALLS
243 fprintf(stderr, "bh done\n");
244 #endif
245 goto rep;
246 }
247
248 #define CHK_BH if (!list_empty(bottom_halves)) check_bottom_halves()
249
250
restrict_fds(void)251 static void restrict_fds(void)
252 {
253 #if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
254 #define RLIMIT_NOFILE RLIMIT_OFILE
255 #endif
256 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
257 struct rlimit limit;
258 int rs;
259 EINTRLOOP(rs, getrlimit(RLIMIT_NOFILE, &limit));
260 if (rs)
261 goto skip_limit;
262 if (limit.rlim_cur > FD_SETSIZE) {
263 limit.rlim_cur = FD_SETSIZE;
264 EINTRLOOP(rs, setrlimit(RLIMIT_NOFILE, &limit));
265 }
266 skip_limit:;
267 #endif
268 }
269
270 unsigned char *sh_file;
271 int sh_line;
272
273 #ifdef USE_LIBEVENT
274
275 static int event_enabled = 0;
276
277 #ifndef HAVE_EVENT_GET_STRUCT_EVENT_SIZE
278 #define sizeof_struct_event sizeof(struct event)
279 #else
280 #define sizeof_struct_event (event_get_struct_event_size())
281 #endif
282
timer_event(struct timer * tm)283 static inline struct event *timer_event(struct timer *tm)
284 {
285 return (struct event *)((unsigned char *)tm - sizeof_struct_event);
286 }
287
288 #ifdef HAVE_EVENT_BASE_SET
289 static struct event_base *event_base;
290 #endif
291
event_callback(int h,short ev,void * data)292 static void event_callback(int h, short ev, void *data)
293 {
294 #ifndef EV_PERSIST
295 if (event_add((struct event *)data, NULL) == -1)
296 fatal_exit("ERROR: event_add failed: %s", strerror(errno));
297 #endif
298 if (!(ev & EV_READ) == !(ev & EV_WRITE))
299 internal_error("event_callback: invalid flags %d on handle %d", (int)ev, h);
300 if (ev & EV_READ) {
301 #if defined(HAVE_LIBEV)
302 /* Old versions of libev badly interact with fork and fire
303 * events spuriously. */
304 if (ev_version_major() < 4 && !can_read(h)) return;
305 #endif
306 pr(threads[h].read_func(threads[h].data)) { }
307 } else {
308 #if defined(HAVE_LIBEV)
309 /* Old versions of libev badly interact with fork and fire
310 * events spuriously. */
311 if (ev_version_major() < 4 && !can_write(h)) return;
312 #endif
313 pr(threads[h].write_func(threads[h].data)) { }
314 }
315 CHK_BH;
316 }
317
timer_callback(int h,short ev,void * data)318 static void timer_callback(int h, short ev, void *data)
319 {
320 struct timer *tm = data;
321 pr(tm->func(tm->data)) { }
322 kill_timer(tm);
323 CHK_BH;
324 }
325
set_event_for_action(int h,void (* func)(void *),struct event ** evptr,short evtype)326 static void set_event_for_action(int h, void (*func)(void *), struct event **evptr, short evtype)
327 {
328 if (func) {
329 if (!*evptr) {
330 #ifdef EV_PERSIST
331 evtype |= EV_PERSIST;
332 #endif
333 *evptr = mem_alloc(sizeof_struct_event);
334 event_set(*evptr, h, evtype, event_callback, *evptr);
335 #ifdef HAVE_EVENT_BASE_SET
336 if (event_base_set(event_base, *evptr) == -1)
337 fatal_exit("ERROR: event_base_set failed: %s at %s:%d, handle %d", strerror(errno), sh_file, sh_line, h);
338 #endif
339 }
340 if (event_add(*evptr, NULL) == -1)
341 fatal_exit("ERROR: event_add failed: %s at %s:%d, handle %d", strerror(errno), sh_file, sh_line, h);
342 } else {
343 if (*evptr) {
344 if (event_del(*evptr) == -1)
345 fatal_exit("ERROR: event_del failed: %s at %s:%d, handle %d", strerror(errno), sh_file, sh_line, h);
346 }
347 }
348 }
349
set_events_for_handle(int h)350 static void set_events_for_handle(int h)
351 {
352 set_event_for_action(h, threads[h].read_func, &threads[h].read_event, EV_READ);
353 set_event_for_action(h, threads[h].write_func, &threads[h].write_event, EV_WRITE);
354 }
355
set_event_for_timer(struct timer * tm)356 static void set_event_for_timer(struct timer *tm)
357 {
358 struct timeval tv;
359 struct event *ev = timer_event(tm);
360 timeout_set(ev, timer_callback, tm);
361 #ifdef HAVE_EVENT_BASE_SET
362 if (event_base_set(event_base, ev) == -1)
363 fatal_exit("ERROR: event_base_set failed: %s", strerror(errno));
364 #endif
365 tv.tv_sec = tm->interval / 1000;
366 tv.tv_usec = (tm->interval % 1000) * 1000;
367 #if defined(HAVE_LIBEV)
368 if (!tm->interval && ev_version_major() < 4) {
369 /* libev bug */
370 tv.tv_usec = 1;
371 }
372 #endif
373 if (timeout_add(ev, &tv) == -1)
374 fatal_exit("ERROR: timeout_add failed: %s", strerror(errno));
375 }
376
enable_libevent(void)377 static void enable_libevent(void)
378 {
379 int i;
380 struct timer *tm;
381 struct list_head *ltm;
382
383 if (disable_libevent)
384 return;
385
386 #if !defined(NO_FORK_ON_EXIT) && defined(HAVE_KQUEUE) && !defined(HAVE_EVENT_REINIT)
387 /* kqueue doesn't work after fork */
388 if (!F)
389 return;
390 #endif
391
392 #if defined(HAVE_EVENT_CONFIG_SET_FLAG)
393 {
394 struct event_config *cfg;
395 cfg = event_config_new();
396 if (!cfg)
397 return;
398 if (event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK) == -1) {
399 event_config_free(cfg);
400 return;
401 }
402 event_base = event_base_new_with_config(cfg);
403 event_config_free(cfg);
404 if (!event_base)
405 return;
406 }
407 #elif defined(HAVE_EVENT_BASE_NEW)
408 event_base = event_base_new();
409 if (!event_base)
410 return;
411 #elif defined(HAVE_EVENT_BASE_SET)
412 event_base = event_init();
413 if (!event_base)
414 return;
415 #else
416 event_init();
417 #endif
418 event_enabled = 1;
419
420 sh_file = (unsigned char *)__FILE__;
421 sh_line = __LINE__;
422 for (i = 0; i < w_max; i++)
423 set_events_for_handle(i);
424
425 foreach(struct timer, tm, ltm, timers)
426 set_event_for_timer(tm);
427 }
428
terminate_libevent(void)429 static void terminate_libevent(void)
430 {
431 int i;
432 if (event_enabled) {
433 for (i = 0; i < n_threads; i++) {
434 set_event_for_action(i, NULL, &threads[i].read_event, EV_READ);
435 if (threads[i].read_event)
436 mem_free(threads[i].read_event);
437 set_event_for_action(i, NULL, &threads[i].write_event, EV_WRITE);
438 if (threads[i].write_event)
439 mem_free(threads[i].write_event);
440 }
441 #ifdef HAVE_EVENT_BASE_FREE
442 event_base_free(event_base);
443 #endif
444 event_enabled = 0;
445 }
446 }
447
do_event_loop(int flags)448 static void do_event_loop(int flags)
449 {
450 int e;
451 #ifdef HAVE_EVENT_BASE_SET
452 e = event_base_loop(event_base, flags);
453 #else
454 e = event_loop(flags);
455 #endif
456 if (e == -1)
457 fatal_exit("ERROR: event_base_loop failed: %s", strerror(errno));
458 }
459
460 #endif
461
add_event_string(unsigned char ** s,int * l,struct terminal * term)462 void add_event_string(unsigned char **s, int *l, struct terminal *term)
463 {
464 #ifdef USE_LIBEVENT
465 if (!event_enabled)
466 #endif
467 add_to_str(s, l, get_text_translation(TEXT_(T_SELECT_SYSCALL), term));
468 #ifdef USE_LIBEVENT
469 if (!event_enabled)
470 add_to_str(s, l, cast_uchar " (");
471 #ifdef HAVE_LIBEVENT
472 add_to_str(s, l, cast_uchar "LibEvent");
473 #elif defined(HAVE_LIBEV)
474 add_to_str(s, l, cast_uchar "LibEv");
475 #else
476 add_to_str(s, l, cast_uchar "LibEvent");
477 #endif
478 #ifdef HAVE_EVENT_GET_VERSION
479 add_chr_to_str(s, l, ' ');
480 {
481 #if defined(HAVE_LIBEV)
482 /* old libev report bogus version */
483 if (!casestrcmp(cast_uchar event_get_version(), cast_uchar "EV_VERSION_MAJOR.EV_VERSION_MINOR")) {
484 add_num_to_str(s, l, ev_version_major());
485 add_chr_to_str(s, l, '.');
486 add_num_to_str(s, l, ev_version_minor());
487 } else
488 #endif
489 add_to_str(s, l, cast_uchar event_get_version());
490 }
491 #endif
492 if (!event_enabled) {
493 add_chr_to_str(s, l, ' ');
494 add_to_str(s, l, get_text_translation(TEXT_(T_dISABLED), term));
495 add_chr_to_str(s, l, ')');
496 } else {
497 #if defined(HAVE_EVENT_BASE_GET_METHOD)
498 add_chr_to_str(s, l, ' ');
499 add_to_str(s, l, cast_uchar event_base_get_method(event_base));
500 #elif defined(HAVE_EVENT_GET_METHOD)
501 add_chr_to_str(s, l, ' ');
502 add_to_str(s, l, cast_uchar event_get_method());
503 #endif
504 }
505 #endif
506 }
507
508
509 static uttime last_time;
510
check_timers(void)511 static void check_timers(void)
512 {
513 uttime interval = get_time() - last_time;
514 struct timer *
515 #ifdef OOPS
516 volatile
517 #endif
518 t; /* volatile because of setjmp */
519 struct list_head *
520 #ifdef OOPS
521 volatile /* volatile because of setjmp */
522 #endif
523 lt;
524 foreach(struct timer, t, lt, timers) {
525 if (t->interval < interval)
526 t->interval = 0;
527 else
528 t->interval -= interval;
529 }
530 while (!list_empty(timers)) {
531 struct timer *t = list_struct(timers.next, struct timer);
532 if (t->interval)
533 break;
534 #ifdef DEBUG_CALLS
535 fprintf(stderr, "call: timer %p\n", t->func);
536 #endif
537 pr(t->func(t->data)) break;
538 #ifdef DEBUG_CALLS
539 fprintf(stderr, "timer done\n");
540 #endif
541 kill_timer(t);
542 CHK_BH;
543 }
544 last_time += interval;
545 }
546
install_timer(uttime t,void (* func)(void *),void * data)547 struct timer *install_timer(uttime t, void (*func)(void *), void *data)
548 {
549 struct timer *tm;
550 #ifdef USE_LIBEVENT
551 {
552 unsigned char *q = mem_alloc(sizeof_struct_event + sizeof(struct timer));
553 tm = (struct timer *)(q + sizeof_struct_event);
554 }
555 #else
556 tm = mem_alloc(sizeof(struct timer));
557 #endif
558 tm->interval = t;
559 tm->func = func;
560 tm->data = data;
561 #ifdef USE_LIBEVENT
562 if (event_enabled) {
563 set_event_for_timer(tm);
564 add_to_list(timers, tm);
565 } else
566 #endif
567 {
568 struct timer *tt;
569 struct list_head *ltt;
570 foreach(struct timer, tt, ltt, timers) if (tt->interval >= t) break;
571 add_before_list_entry(ltt, &tm->list_entry);
572 }
573 return tm;
574 }
575
kill_timer(struct timer * tm)576 void kill_timer(struct timer *tm)
577 {
578 del_from_list(tm);
579 #ifdef USE_LIBEVENT
580 if (event_enabled)
581 timeout_del(timer_event(tm));
582 mem_free(timer_event(tm));
583 #else
584 mem_free(tm);
585 #endif
586 }
587
get_handler(int fd,int tp)588 void (*get_handler(int fd, int tp))(void *)
589 {
590 if (fd < 0)
591 internal_error("get_handler: handle %d", fd);
592 if (fd >= w_max)
593 return NULL;
594 switch (tp) {
595 case H_READ: return threads[fd].read_func;
596 case H_WRITE: return threads[fd].write_func;
597 }
598 internal_error("get_handler: bad type %d", tp);
599 return NULL;
600 }
601
get_handler_data(int fd)602 void *get_handler_data(int fd)
603 {
604 if (fd < 0)
605 internal_error("get_handler: handle %d", fd);
606 if (fd >= w_max)
607 return NULL;
608 return threads[fd].data;
609 }
610
set_handlers_file_line(int fd,void (* read_func)(void *),void (* write_func)(void *),void * data)611 void set_handlers_file_line(int fd, void (*read_func)(void *), void (*write_func)(void *), void *data)
612 {
613 if (fd < 0)
614 goto invl;
615 #if defined(DEBUG) && !defined(socket)
616 {
617 struct stat st;
618 int rs;
619 EINTRLOOP(rs, fstat(fd, &st));
620 if (rs == -1 && errno == EBADF) {
621 goto invl;
622 }
623 }
624 #endif
625 #if defined(USE_POLL) && defined(USE_LIBEVENT)
626 if (!event_enabled)
627 #endif
628 if (fd >= (int)FD_SETSIZE) {
629 fatal_exit("too big handle %d at %s:%d", fd, sh_file, sh_line);
630 return;
631 }
632 if (fd >= n_threads) {
633 if ((unsigned)fd > (unsigned)MAXINT / sizeof(struct thread) - 1) overalloc();
634 threads = mem_realloc(threads, (fd + 1) * sizeof(struct thread));
635 memset(threads + n_threads, 0, (fd + 1 - n_threads) * sizeof(struct thread));
636 n_threads = fd + 1;
637 }
638 if (threads[fd].read_func == read_func && threads[fd].write_func == write_func && threads[fd].data == data)
639 return;
640 threads[fd].read_func = read_func;
641 threads[fd].write_func = write_func;
642 threads[fd].data = data;
643 if (read_func || write_func) {
644 if (fd >= w_max) w_max = fd + 1;
645 } else if (fd == w_max - 1) {
646 int i;
647 for (i = fd - 1; i >= 0; i--)
648 if (threads[i].read_func || threads[i].write_func)
649 break;
650 w_max = i + 1;
651 }
652 #ifdef USE_LIBEVENT
653 if (event_enabled) {
654 set_events_for_handle(fd);
655 return;
656 }
657 #endif
658 if (read_func) FD_SET(fd, &w_read);
659 else {
660 FD_CLR(fd, &w_read);
661 FD_CLR(fd, &x_read);
662 }
663 if (write_func) FD_SET(fd, &w_write);
664 else {
665 FD_CLR(fd, &w_write);
666 FD_CLR(fd, &x_write);
667 }
668 return;
669
670 invl:
671 internal_error("invalid set_handlers call at %s:%d: %d, %p, %p, %p", sh_file, sh_line, fd, read_func, write_func, data);
672 }
673
clear_events(int h,int blocking)674 void clear_events(int h, int blocking)
675 {
676 #if !defined(O_NONBLOCK) && !defined(FIONBIO)
677 blocking = 1;
678 #endif
679 while (blocking ? can_read(h) : 1) {
680 unsigned char c[64];
681 int rd;
682 EINTRLOOP(rd, (int)read(h, c, sizeof c));
683 if (rd != sizeof c) break;
684 }
685 }
686
687 #if defined(NSIG) && NSIG > 32
688 #define NUM_SIGNALS NSIG
689 #else
690 #define NUM_SIGNALS 32
691 #endif
692
693 #ifndef NO_SIGNAL_HANDLERS
694
clear_events_ptr(void * handle)695 static void clear_events_ptr(void *handle)
696 {
697 clear_events((int)(my_intptr_t)handle, 0);
698 }
699
700
701 struct signal_handler {
702 void (*fn)(void *);
703 void *data;
704 int critical;
705 };
706
707 static volatile int signal_mask[NUM_SIGNALS];
708 static volatile struct signal_handler signal_handlers[NUM_SIGNALS];
709
710 static pid_t signal_pid;
711 int signal_pipe[2] = { -1, -1 };
712
got_signal(int sig)713 SIGNAL_HANDLER static void got_signal(int sig)
714 {
715 void (*fn)(void *);
716 int sv_errno = errno;
717 /*fprintf(stderr, "ERROR: signal number: %d\n", sig);*/
718
719 #if !defined(HAVE_SIGACTION)
720 do_signal(sig, got_signal);
721 #endif
722
723 /* if we get signal from a forked child, don't do anything */
724 if (getpid() != signal_pid) goto ret;
725
726 if (sig >= NUM_SIGNALS || sig < 0) {
727 /*error("ERROR: bad signal number: %d", sig);*/
728 goto ret;
729 }
730 fn = signal_handlers[sig].fn;
731 if (!fn) goto ret;
732 if (signal_handlers[sig].critical) {
733 fn(signal_handlers[sig].data);
734 goto ret;
735 }
736 signal_mask[sig] = 1;
737 if (can_write(signal_pipe[1])) {
738 int wr;
739 EINTRLOOP(wr, (int)write(signal_pipe[1], "", 1));
740 }
741 ret:
742 errno = sv_errno;
743 }
744
745 #ifdef HAVE_SIGACTION
746 static struct sigaction sa_zero;
747 #endif
748
749 #endif
750
install_signal_handler(int sig,void (* fn)(void *),void * data,int critical)751 void install_signal_handler(int sig, void (*fn)(void *), void *data, int critical)
752 {
753 #if defined(NO_SIGNAL_HANDLERS)
754 #elif defined(HAVE_SIGACTION)
755 int rs;
756 struct sigaction sa = sa_zero;
757 /*debug("install (%d) -> %p,%d", sig, fn, critical);*/
758 if (sig >= NUM_SIGNALS || sig < 0) {
759 internal_error("bad signal number: %d", sig);
760 return;
761 }
762 if (!fn) sa.sa_handler = SIG_IGN;
763 else sa.sa_handler = (void (*)(int))got_signal;
764 sig_fill_set(&sa.sa_mask);
765 sa.sa_flags = SA_RESTART;
766 if (!fn)
767 EINTRLOOP(rs, sigaction(sig, &sa, NULL));
768 signal_handlers[sig].fn = fn;
769 signal_handlers[sig].data = data;
770 signal_handlers[sig].critical = critical;
771 if (fn)
772 EINTRLOOP(rs, sigaction(sig, &sa, NULL));
773 #else
774 if (!fn) do_signal(sig, SIG_IGN);
775 signal_handlers[sig].fn = fn;
776 signal_handlers[sig].data = data;
777 signal_handlers[sig].critical = critical;
778 if (fn) do_signal(sig, got_signal);
779 #endif
780 }
781
interruptible_signal(int sig,int in)782 void interruptible_signal(int sig, int in)
783 {
784 #if defined(HAVE_SIGACTION) && !defined(NO_SIGNAL_HANDLERS)
785 struct sigaction sa = sa_zero;
786 int rs;
787 if (sig >= NUM_SIGNALS || sig < 0) {
788 internal_error("bad signal number: %d", sig);
789 return;
790 }
791 if (!signal_handlers[sig].fn) return;
792 sa.sa_handler = (void (*)(int))got_signal;
793 sig_fill_set(&sa.sa_mask);
794 if (!in) sa.sa_flags = SA_RESTART;
795 EINTRLOOP(rs, sigaction(sig, &sa, NULL));
796 #endif
797 }
798
799 static sigset_t sig_old_mask;
800 static int sig_unblock = 0;
801
block_signals(int except1,int except2)802 void block_signals(int except1, int except2)
803 {
804 int rs;
805 sigset_t mask;
806 sig_fill_set(&mask);
807 #ifdef HAVE_SIGDELSET
808 if (except1) sigdelset(&mask, except1);
809 if (except2) sigdelset(&mask, except2);
810 #ifdef SIGILL
811 sigdelset(&mask, SIGILL);
812 #endif
813 #ifdef SIGABRT
814 sigdelset(&mask, SIGABRT);
815 #endif
816 #ifdef SIGFPE
817 sigdelset(&mask, SIGFPE);
818 #endif
819 #ifdef SIGSEGV
820 sigdelset(&mask, SIGSEGV);
821 #endif
822 #ifdef SIGBUS
823 sigdelset(&mask, SIGBUS);
824 #endif
825 #else
826 if (except1 || except2) return;
827 #endif
828 EINTRLOOP(rs, do_sigprocmask(SIG_BLOCK, &mask, &sig_old_mask));
829 if (!rs) sig_unblock = 1;
830 }
831
unblock_signals(void)832 void unblock_signals(void)
833 {
834 int rs;
835 if (sig_unblock) {
836 EINTRLOOP(rs, do_sigprocmask(SIG_SETMASK, &sig_old_mask, NULL));
837 sig_unblock = 0;
838 }
839 }
840
check_signals(void)841 static int check_signals(void)
842 {
843 int r = 0;
844 #ifndef NO_SIGNAL_HANDLERS
845 volatile int i; /* volatile because of setjmp */
846 for (i = 0; i < NUM_SIGNALS; i++)
847 if (signal_mask[i]) {
848 signal_mask[i] = 0;
849 if (signal_handlers[i].fn) {
850 #ifdef DEBUG_CALLS
851 fprintf(stderr, "call: signal %d -> %p\n", i, signal_handlers[i].fn);
852 #endif
853 pr(signal_handlers[i].fn(signal_handlers[i].data)) {
854 #ifdef OOPS
855 return 1;
856 #endif
857 }
858 #ifdef DEBUG_CALLS
859 fprintf(stderr, "signal done\n");
860 #endif
861 }
862 CHK_BH;
863 r = 1;
864 }
865 #endif
866 return r;
867 }
868
869 #ifdef SIGCHLD
sigchld(void * p)870 static void sigchld(void *p)
871 {
872 pid_t pid;
873 #ifndef WNOHANG
874 EINTRLOOP(pid, wait(NULL));
875 #else
876 do {
877 EINTRLOOP(pid, waitpid(-1, NULL, WNOHANG));
878 } while (pid > 0);
879 #endif
880 }
881
set_sigcld(void)882 void set_sigcld(void)
883 {
884 install_signal_handler(SIGCHLD, sigchld, NULL, 1);
885 }
886 #else
set_sigcld(void)887 void set_sigcld(void)
888 {
889 }
890 #endif
891
892 #ifdef HAVE_OPENMP
893
894 static int num_threads = -1;
895
omp_start(void)896 int omp_start(void)
897 {
898 int thr;
899 if (disable_openmp || num_threads == 1)
900 return 1;
901 block_signals(0, 0);
902 if (num_threads != -1)
903 return num_threads;
904 omp_set_dynamic(0);
905 thr = omp_get_max_threads();
906 if (thr > OPENMP_MAX_THREADS)
907 thr = OPENMP_MAX_THREADS;
908 omp_set_num_threads(thr);
909 if (thr > 1) {
910 #pragma omp parallel shared(thr)
911 #pragma omp single
912 thr = omp_get_num_threads();
913 omp_set_num_threads(thr);
914 }
915 num_threads = thr;
916 if (thr == 1)
917 unblock_signals();
918 return thr;
919 }
920
omp_end(void)921 void omp_end(void)
922 {
923 if (disable_openmp || num_threads == 1)
924 return;
925 unblock_signals();
926 }
927
928 #endif
929
reinit_child(void)930 void reinit_child(void)
931 {
932 #if !defined(NO_SIGNAL_HANDLERS)
933 signal_pid = getpid();
934 #endif
935 #ifdef USE_LIBEVENT
936 if (event_enabled) {
937 #ifdef HAVE_EVENT_REINIT
938 if (event_reinit(event_base))
939 fatal_exit("ERROR: event_reinit failed: %s", strerror(errno));
940 #endif
941 }
942 #endif
943 }
944
945 int terminate_loop = 0;
946
select_loop(void (* init)(void))947 void select_loop(void (*init)(void))
948 {
949 #if !defined(USE_LIBEVENT) || !defined(USE_POLL)
950 restrict_fds();
951 #endif
952
953 #if !defined(NO_SIGNAL_HANDLERS)
954 #if defined(HAVE_SIGACTION)
955 memset(&sa_zero, 0, sizeof sa_zero);
956 #endif
957 memset((void *)signal_mask, 0, sizeof signal_mask);
958 memset((void *)signal_handlers, 0, sizeof signal_handlers);
959 #endif
960 FD_ZERO(&w_read);
961 FD_ZERO(&w_write);
962 w_max = 0;
963 last_time = get_time();
964 ignore_signals();
965 #if !defined(NO_SIGNAL_HANDLERS)
966 signal_pid = getpid();
967 if (c_pipe(signal_pipe)) {
968 fatal_exit("ERROR: can't create pipe for signal handling");
969 }
970 set_nonblock(signal_pipe[0]);
971 set_nonblock(signal_pipe[1]);
972 set_handlers(signal_pipe[0], clear_events_ptr, NULL, (void *)(my_intptr_t)signal_pipe[0]);
973 #endif
974 init();
975 CHK_BH;
976
977 #ifdef USE_LIBEVENT
978 #ifdef G
979 if (!F || !(drv->flags & GD_NO_LIBEVENT))
980 #endif
981 {
982 enable_libevent();
983 }
984 #if defined(USE_POLL)
985 if (!event_enabled) {
986 restrict_fds();
987 }
988 #endif
989 if (event_enabled) {
990 while (!terminate_loop) {
991 check_signals();
992 if (!F) {
993 do_event_loop(EVLOOP_NONBLOCK);
994 check_signals();
995 redraw_all_terminals();
996 }
997 if (terminate_loop) break;
998 test_detach_console();
999 do_event_loop(EVLOOP_ONCE);
1000 }
1001 nopr();
1002 } else
1003 #endif
1004
1005 while (!terminate_loop) {
1006 volatile int n, i; /* volatile because of setjmp */
1007 int ww_max;
1008 struct timeval tv;
1009 struct timeval *tm = NULL;
1010 check_signals();
1011 check_timers();
1012 if (!F) redraw_all_terminals();
1013 test_detach_console();
1014 #ifdef OS_BAD_SIGNALS
1015 /* Cygwin has buggy signals that sometimes don't interrupt select.
1016 So don't wait indefinitely in it. */
1017 tv.tv_sec = 1;
1018 tv.tv_usec = 0;
1019 tm = &tv;
1020 #endif
1021 if (!list_empty(timers)) {
1022 uttime tt = list_struct(timers.next, struct timer)->interval + 1;
1023 #ifdef OS_BAD_SIGNALS
1024 if (tt < 1000)
1025 #endif
1026 {
1027 tv.tv_sec = tt / 1000 < MAXINT ? (int)(tt / 1000) : MAXINT;
1028 tv.tv_usec = (tt % 1000) * 1000;
1029 tm = &tv;
1030 }
1031 }
1032 memcpy(&x_read, &w_read, sizeof(fd_set));
1033 memcpy(&x_write, &w_write, sizeof(fd_set));
1034 if (terminate_loop) break;
1035 /*if (!w_max && list_empty(timers)) {
1036 break;
1037 }*/
1038 /*{
1039 int i;
1040 printf("\nR:");
1041 for (i = 0; i < 256; i++) if (FD_ISSET(i, &x_read)) printf("%d,", i);
1042 printf("\nW:");
1043 for (i = 0; i < 256; i++) if (FD_ISSET(i, &x_write)) printf("%d,", i);
1044 fflush(stdout);
1045 }*/
1046 #ifdef DEBUG_CALLS
1047 fprintf(stderr, "select\n");
1048 #endif
1049 ww_max = w_max;
1050 if ((n = loop_select(w_max, &x_read, &x_write, NULL, tm)) < 0) {
1051 #ifdef DEBUG_CALLS
1052 fprintf(stderr, "select intr\n");
1053 #endif
1054 if (errno != EINTR) {
1055 fatal_exit("ERROR: select failed: %s", strerror(errno));
1056 }
1057 continue;
1058 }
1059 #ifdef DEBUG_CALLS
1060 fprintf(stderr, "select done\n");
1061 #endif
1062 check_signals();
1063 check_timers();
1064 /*
1065 * EMX has broken select. It should return the total number of
1066 * bits set, but instead it returns the number of handles for
1067 * which some activity is reported.
1068 * Sometimes it returns unusually high values.
1069 */
1070 i = -1;
1071 while (n > 0 && ++i < ww_max) {
1072 int k = 0;
1073 if (FD_ISSET(i, &x_read)) {
1074 if (threads[i].read_func) {
1075 #ifdef DEBUG_CALLS
1076 fprintf(stderr, "call: read %d -> %p\n", i, threads[i].read_func);
1077 #endif
1078 pr(threads[i].read_func(threads[i].data)) continue;
1079 #ifdef DEBUG_CALLS
1080 fprintf(stderr, "read done\n");
1081 #endif
1082 CHK_BH;
1083 }
1084 k = 1;
1085 }
1086 if (FD_ISSET(i, &x_write)) {
1087 if (threads[i].write_func) {
1088 #ifdef DEBUG_CALLS
1089 fprintf(stderr, "call: write %d -> %p\n", i, threads[i].write_func);
1090 #endif
1091 pr(threads[i].write_func(threads[i].data)) continue;
1092 #ifdef DEBUG_CALLS
1093 fprintf(stderr, "write done\n");
1094 #endif
1095 CHK_BH;
1096 }
1097 k = 1;
1098 }
1099 n -= k;
1100 }
1101 nopr();
1102 }
1103 #ifdef DEBUG_CALLS
1104 fprintf(stderr, "exit loop\n");
1105 #endif
1106 nopr();
1107 }
1108
terminate_select(void)1109 void terminate_select(void)
1110 {
1111 #ifdef USE_LIBEVENT
1112 terminate_libevent();
1113 #endif
1114 mem_free(threads);
1115 }
1116