1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2016-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25
26 // These functions may be provided by gnulib. We don't include gnulib
27 // headers directly in Octave's C++ source files to avoid problems that
28 // may be caused by the way that gnulib overrides standard library
29 // functions.
30
31 #if defined (HAVE_CONFIG_H)
32 # include "config.h"
33 #endif
34
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #if defined (__WIN32__) && ! defined (__CYGWIN__)
42 # include <windows.h>
43 #else
44 # include <pthread.h>
45 #endif
46
47 #include "signal-wrappers.h"
48
49 int
octave_kill_wrapper(pid_t pid,int signum)50 octave_kill_wrapper (pid_t pid, int signum)
51 {
52 #if defined (HAVE_KILL)
53 return kill (pid, signum);
54 #else
55
56 octave_unused_parameter (pid);
57 octave_unused_parameter (signum);
58
59 return -1;
60 #endif
61 }
62
63 char *
octave_strsignal_wrapper(int signum)64 octave_strsignal_wrapper (int signum)
65 {
66 return strsignal (signum);
67 }
68
69 bool
octave_have_kill(void)70 octave_have_kill (void)
71 {
72 #if defined (HAVE_KILL)
73 return true;
74 #else
75 return false;
76 #endif
77 }
78
79 bool
octave_get_sig_number(const char * signame,int * signum)80 octave_get_sig_number (const char *signame, int *signum)
81 {
82 *signum = -1;
83
84 // FIXME: this should probably use a perfect hash function.
85
86 if (! strcmp (signame, "SIGINT"))
87 {
88 #if defined (SIGINT)
89 *signum = SIGINT;
90 return true;
91 #endif
92 }
93 else if (! strcmp (signame, "SIGBREAK"))
94 {
95 #if defined (SIGBREAK)
96 *signum = SIGBREAK;
97 return true;
98 #endif
99 }
100 else if (! strcmp (signame, "SIGABRT"))
101 {
102 #if defined (SIGABRT)
103 *signum = SIGABRT;
104 return true;
105 #endif
106 }
107 else if (! strcmp (signame, "SIGALRM"))
108 {
109 #if defined (SIGALRM)
110 *signum = SIGALRM;
111 return true;
112 #endif
113 }
114 else if (! strcmp (signame, "SIGBUS"))
115 {
116 #if defined (SIGBUS)
117 *signum = SIGBUS;
118 return true;
119 #endif
120 }
121 else if (! strcmp (signame, "SIGCHLD"))
122 {
123 #if defined (SIGCHLD)
124 *signum = SIGCHLD;
125 return true;
126 #endif
127 }
128 else if (! strcmp (signame, "SIGCLD"))
129 {
130 #if defined (SIGCLD)
131 *signum = SIGCLD;
132 return true;
133 #endif
134 }
135 else if (! strcmp (signame, "SIGCONT"))
136 {
137 #if defined (SIGCONT)
138 *signum = SIGCONT;
139 return true;
140 #endif
141 }
142 else if (! strcmp (signame, "SIGEMT"))
143 {
144 #if defined (SIGEMT)
145 *signum = SIGEMT;
146 return true;
147 #endif
148 }
149 else if (! strcmp (signame, "SIGFPE"))
150 {
151 #if defined (SIGFPE)
152 *signum = SIGFPE;
153 return true;
154 #endif
155 }
156 else if (! strcmp (signame, "SIGHUP"))
157 {
158 #if defined (SIGHUP)
159 *signum = SIGHUP;
160 return true;
161 #endif
162 }
163 else if (! strcmp (signame, "SIGILL"))
164 {
165 #if defined (SIGILL)
166 *signum = SIGILL;
167 return true;
168 #endif
169 }
170 else if (! strcmp (signame, "SIGINFO"))
171 {
172 #if defined (SIGINFO)
173 *signum = SIGINFO;
174 return true;
175 #endif
176 }
177 else if (! strcmp (signame, "SIGIOT"))
178 {
179 #if defined (SIGIOT)
180 *signum = SIGIOT;
181 return true;
182 #endif
183 }
184 else if (! strcmp (signame, "SIGKILL"))
185 {
186 #if defined (SIGKILL)
187 *signum = SIGKILL;
188 return true;
189 #endif
190 }
191 else if (! strcmp (signame, "SIGLOST"))
192 {
193 #if defined (SIGLOST)
194 *signum = SIGLOST;
195 return true;
196 #endif
197 }
198 else if (! strcmp (signame, "SIGPIPE"))
199 {
200 #if defined (SIGPIPE)
201 *signum = SIGPIPE;
202 return true;
203 #endif
204 }
205 else if (! strcmp (signame, "SIGPOLL"))
206 {
207 #if defined (SIGPOLL)
208 *signum = SIGPOLL;
209 return true;
210 #endif
211 }
212 else if (! strcmp (signame, "SIGPROF"))
213 {
214 #if defined (SIGPROF)
215 *signum = SIGPROF;
216 return true;
217 #endif
218 }
219 else if (! strcmp (signame, "SIGPWR"))
220 {
221 #if defined (SIGPWR)
222 *signum = SIGPWR;
223 return true;
224 #endif
225 }
226 else if (! strcmp (signame, "SIGQUIT"))
227 {
228 #if defined (SIGQUIT)
229 *signum = SIGQUIT;
230 return true;
231 #endif
232 }
233 else if (! strcmp (signame, "SIGSEGV"))
234 {
235 #if defined (SIGSEGV)
236 *signum = SIGSEGV;
237 return true;
238 #endif
239 }
240 else if (! strcmp (signame, "SIGSTOP"))
241 {
242 #if defined (SIGSTOP)
243 *signum = SIGSTOP;
244 return true;
245 #endif
246 }
247 else if (! strcmp (signame, "SIGSYS"))
248 {
249 #if defined (SIGSYS)
250 *signum = SIGSYS;
251 return true;
252 #endif
253 }
254 else if (! strcmp (signame, "SIGTERM"))
255 {
256 #if defined (SIGTERM)
257 *signum = SIGTERM;
258 return true;
259 #endif
260 }
261 else if (! strcmp (signame, "SIGTRAP"))
262 {
263 #if defined (SIGTRAP)
264 *signum = SIGTRAP;
265 return true;
266 #endif
267 }
268 else if (! strcmp (signame, "SIGTSTP"))
269 {
270 #if defined (SIGTSTP)
271 *signum = SIGTSTP;
272 return true;
273 #endif
274 }
275 else if (! strcmp (signame, "SIGTTIN"))
276 {
277 #if defined (SIGTTIN)
278 *signum = SIGTTIN;
279 return true;
280 #endif
281 }
282 else if (! strcmp (signame, "SIGTTOU"))
283 {
284 #if defined (SIGTTOU)
285 *signum = SIGTTOU;
286 return true;
287 #endif
288 }
289 else if (! strcmp (signame, "SIGURG"))
290 {
291 #if defined (SIGURG)
292 *signum = SIGURG;
293 return true;
294 #endif
295 }
296 else if (! strcmp (signame, "SIGUSR1"))
297 {
298 #if defined (SIGUSR1)
299 *signum = SIGUSR1;
300 return true;
301 #endif
302 }
303 else if (! strcmp (signame, "SIGUSR2"))
304 {
305 #if defined (SIGUSR2)
306 *signum = SIGUSR2;
307 return true;
308 #endif
309 }
310 else if (! strcmp (signame, "SIGVTALRM"))
311 {
312 #if defined (SIGVTALRM)
313 *signum = SIGVTALRM;
314 return true;
315 #endif
316 }
317 else if (! strcmp (signame, "SIGIO"))
318 {
319 #if defined (SIGIO)
320 *signum = SIGIO;
321 return true;
322 #endif
323 }
324 else if (! strcmp (signame, "SIGWINCH"))
325 {
326 #if defined (SIGWINCH)
327 *signum = SIGWINCH;
328 return true;
329 #endif
330 }
331 else if (! strcmp (signame, "SIGXCPU"))
332 {
333 #if defined (SIGXCPU)
334 *signum = SIGXCPU;
335 return true;
336 #endif
337 }
338 else if (! strcmp (signame, "SIGXFSZ"))
339 {
340 #if defined (SIGXFSZ)
341 *signum = SIGXFSZ;
342 return true;
343 #endif
344 }
345
346 return false;
347 }
348
349 octave_sig_handler *
octave_set_signal_handler_internal(int sig,octave_sig_handler * handler,bool restart_syscalls)350 octave_set_signal_handler_internal (int sig, octave_sig_handler *handler,
351 bool restart_syscalls)
352 {
353 struct sigaction act, oact;
354
355 act.sa_handler = handler;
356 act.sa_flags = 0;
357
358 #if defined (SIGALRM)
359 if (sig == SIGALRM)
360 {
361 # if defined (SA_INTERRUPT)
362 act.sa_flags |= SA_INTERRUPT;
363 # endif
364 }
365 #endif
366 #if defined (SA_RESTART)
367 # if defined (SIGALRM)
368 else
369 # endif
370 // FIXME: Do we also need to explicitly disable SA_RESTART?
371 if (restart_syscalls)
372 act.sa_flags |= SA_RESTART;
373 #endif
374
375 sigemptyset (&act.sa_mask);
376 sigemptyset (&oact.sa_mask);
377
378 sigaction (sig, &act, &oact);
379
380 return oact.sa_handler;
381 }
382
383 octave_sig_handler *
octave_set_signal_handler_by_name(const char * signame,octave_sig_handler * handler,bool restart_syscalls)384 octave_set_signal_handler_by_name (const char *signame,
385 octave_sig_handler *handler,
386 bool restart_syscalls)
387 {
388 int sig;
389
390 return (octave_get_sig_number (signame, &sig)
391 ? octave_set_signal_handler_internal (sig, handler, restart_syscalls)
392 : 0);
393 }
394
395 octave_sig_handler *
octave_set_default_signal_handler(int sig)396 octave_set_default_signal_handler (int sig)
397 {
398 return octave_set_signal_handler_internal (sig, SIG_DFL, true);
399 }
400
401 octave_sig_handler *
octave_set_default_signal_handler_by_name(const char * signame)402 octave_set_default_signal_handler_by_name (const char *signame)
403 {
404 return octave_set_signal_handler_by_name (signame, SIG_DFL, true);
405 }
406
407 int
octave_num_signals(void)408 octave_num_signals (void)
409 {
410 return NSIG;
411 }
412
413 typedef struct
414 {
415 sigset_t nvar;
416 sigset_t ovar;
417 } sigset_info;
418
419 void *
octave_block_child(void)420 octave_block_child (void)
421 {
422 #if defined (SIGCHLD) || defined (SIGCLD)
423
424 sigset_info *context = (sigset_info *) malloc (sizeof (sigset_info));
425
426 if (context)
427 {
428 sigemptyset (&(context->ovar));
429 sigemptyset (&(context->nvar));
430 #if defined (SIGCHLD)
431 sigaddset (&(context->nvar), SIGCHLD);
432 #endif
433 #if defined (SIGCLD)
434 sigaddset (&(context->nvar), SIGCLD);
435 #endif
436 sigprocmask (SIG_BLOCK, &(context->nvar), &(context->ovar));
437 }
438
439 return context;
440
441 #else
442
443 return 0;
444
445 #endif
446 }
447
448 void
octave_unblock_child(void * context_arg)449 octave_unblock_child (void *context_arg)
450 {
451 if (context_arg)
452 {
453 sigset_info *context = (sigset_info *) context_arg;
454
455 sigprocmask (SIG_SETMASK, &(context->ovar), 0);
456
457 free (context);
458 }
459 }
460
461 static void
block_or_unblock_signal(int how,int sig)462 block_or_unblock_signal (int how, int sig)
463 {
464 #if ! defined (__WIN32__) || defined (__CYGWIN__)
465
466 // Blocking/unblocking signals at thread level is only supported
467 // on platform with fully compliant POSIX threads. This is not
468 // supported on Win32. Moreover, we have to make sure that SIGINT
469 // handler is not installed before calling AllocConsole: installing
470 // a SIGINT handler internally calls SetConsoleCtrlHandler, which
471 // must be called after AllocConsole to be effective.
472
473 sigset_t signal_mask;
474
475 sigemptyset (&signal_mask);
476
477 sigaddset (&signal_mask, sig);
478
479 pthread_sigmask (how, &signal_mask, 0);
480
481 #else
482
483 octave_unused_parameter (how);
484 octave_unused_parameter (sig);
485
486 #endif
487 }
488
489 void
octave_block_interrupt_signal(void)490 octave_block_interrupt_signal (void)
491 {
492 block_or_unblock_signal (SIG_BLOCK, SIGINT);
493
494 #if defined (SIGBREAK)
495 block_or_unblock_signal (SIG_BLOCK, SIGBREAK);
496 #endif
497 }
498
499 void
octave_unblock_interrupt_signal(void)500 octave_unblock_interrupt_signal (void)
501 {
502 block_or_unblock_signal (SIG_UNBLOCK, SIGINT);
503
504 #if defined (SIGBREAK)
505 block_or_unblock_signal (SIG_UNBLOCK, SIGBREAK);
506 #endif
507 }
508
509 static void
block_or_unblock_signal_by_name(int how,const char * signame)510 block_or_unblock_signal_by_name (int how, const char *signame)
511 {
512 int sig;
513
514 if (octave_get_sig_number (signame, &sig))
515 block_or_unblock_signal (how, sig);
516 }
517
518 void
octave_block_signal_by_name(const char * signame)519 octave_block_signal_by_name (const char *signame)
520 {
521 block_or_unblock_signal_by_name (SIG_BLOCK, signame);
522 }
523
524 void
octave_unblock_signal_by_name(const char * signame)525 octave_unblock_signal_by_name (const char *signame)
526 {
527 block_or_unblock_signal_by_name (SIG_UNBLOCK, signame);
528 }
529
530 /* Allow us to save the signal mask and then restore it to the most
531 recently saved value. This is necessary when using the POSIX signal
532 handling interface on some systems calling longjmp out of the signal
533 handler to get to the top level on an interrupt doesn't restore the
534 original signal mask. Alternatively, we could use
535 sigsetjmp/siglongjmp, but saving and restoring the signal mask
536 ourselves works ok and seems simpler just now. */
537
538 static sigset_t octave_signal_mask;
539
540 void
octave_save_signal_mask(void)541 octave_save_signal_mask (void)
542 {
543 sigprocmask (0, 0, &octave_signal_mask);
544 }
545
546 void
octave_restore_signal_mask(void)547 octave_restore_signal_mask (void)
548 {
549 sigprocmask (SIG_SETMASK, &octave_signal_mask, 0);
550 }
551
552 void *
octave_alloc_signal_mask(void)553 octave_alloc_signal_mask (void)
554 {
555 return malloc (sizeof (sigset_t));
556 }
557
558 void
octave_free_signal_mask(void * mask)559 octave_free_signal_mask (void *mask)
560 {
561 free (mask);
562 }
563
564 void
octave_get_signal_mask(void * mask)565 octave_get_signal_mask (void *mask)
566 {
567 sigprocmask (0, 0, mask);
568 }
569
570 void
octave_set_signal_mask(void * mask)571 octave_set_signal_mask (void *mask)
572 {
573 sigprocmask (SIG_SETMASK, (sigset_t *) mask, 0);
574 }
575
576 #if ! defined (__WIN32__)
577 static const sigset_t *
octave_async_signals(void)578 octave_async_signals (void)
579 {
580 static bool initialized = false;
581 static sigset_t sigmask;
582
583 if (! initialized)
584 {
585 sigemptyset (&sigmask);
586
587 // The signals listed here should match the list of signals that
588 // we handle in the signal handler thread.
589
590 // Interrupt signals.
591
592 #if defined (SIGINT)
593 sigaddset (&sigmask, SIGINT);
594 #endif
595
596 #if defined (SIGBREAK)
597 sigaddset (&sigmask, SIGBREAK);
598 #endif
599
600 // Termination signals.
601
602 #if defined (SIGHUP)
603 sigaddset (&sigmask, SIGHUP);
604 #endif
605
606 #if defined (SIGQUIT)
607 sigaddset (&sigmask, SIGQUIT);
608 #endif
609
610 #if defined (SIGTERM)
611 sigaddset (&sigmask, SIGTERM);
612 #endif
613
614 // Alarm signals.
615
616 #if defined (SIGALRM)
617 sigaddset (&sigmask, SIGALRM);
618 #endif
619
620 #if defined (SIGVTALRM)
621 sigaddset (&sigmask, SIGVTALRM);
622 #endif
623
624 // I/O signals.
625
626 #if defined (SIGLOST)
627 sigaddset (&sigmask, SIGLOST);
628 #endif
629
630 #if defined (SIGPIPE)
631 sigaddset (&sigmask, SIGPIPE);
632 #endif
633
634 // Job control signals.
635
636 #if defined (SIGCHLD)
637 sigaddset (&sigmask, SIGCHLD);
638 #endif
639
640 #if defined (SIGCLD)
641 sigaddset (&sigmask, SIGCLD);
642 #endif
643
644 // Resource limit signals.
645
646 #if defined (SIGXCPU)
647 sigaddset (&sigmask, SIGXCPU);
648 #endif
649
650 #if defined (SIGXFSZ)
651 sigaddset (&sigmask, SIGXFSZ);
652 #endif
653
654 initialized = true;
655 }
656
657 return &sigmask;
658 }
659 #endif
660
661 void
octave_block_async_signals(void)662 octave_block_async_signals (void)
663 {
664 #if ! defined (__WIN32__) || defined (__CYGWIN__)
665 pthread_sigmask (SIG_BLOCK, octave_async_signals (), 0);
666 #endif
667 }
668
669 void
octave_unblock_async_signals(void)670 octave_unblock_async_signals (void)
671 {
672 #if ! defined (__WIN32__) || defined (__CYGWIN__)
673 pthread_sigmask (SIG_UNBLOCK, octave_async_signals (), 0);
674 #endif
675 }
676
677 int
octave_raise_wrapper(int signum)678 octave_raise_wrapper (int signum)
679 {
680 return raise (signum);
681 }
682
683 #if ! defined (__WIN32__)
684 static void *
signal_watcher(void * arg)685 signal_watcher (void *arg)
686 {
687 octave_sig_handler *handler = (octave_sig_handler *) arg;
688
689 octave_unblock_async_signals ();
690
691 const sigset_t *async_signals = octave_async_signals ();
692
693 while (1)
694 {
695 int sig_caught;
696
697 if (sigwait (async_signals, &sig_caught))
698 {
699 // FIXME: what else should we do?
700 abort ();
701 }
702
703 // Let handler have complete control over what to do.
704 (*handler) (sig_caught);
705 }
706 }
707 #endif
708
709 void
octave_create_interrupt_watcher_thread(octave_sig_handler * handler)710 octave_create_interrupt_watcher_thread (octave_sig_handler *handler)
711 {
712 #if ! defined (__WIN32__)
713 pthread_t sighandler_thread_id;
714
715 if (pthread_create (&sighandler_thread_id, 0, signal_watcher, handler))
716 {
717 // FIXME: what else should we do?
718 abort ();
719 }
720 #else
721 octave_unblock_async_signals ();
722
723 octave_unused_parameter (handler);
724 #endif
725 }
726
727 #if ! defined (__WIN32__)
728 static void
print_sigset(FILE * of,const char * prefix,const sigset_t * sigset)729 print_sigset (FILE *of, const char *prefix, const sigset_t *sigset)
730 {
731 int sig;
732 int cnt = 0;
733
734 for (sig = 1; sig < NSIG; sig++)
735 {
736 if (sigismember (sigset, sig))
737 {
738 cnt++;
739 fprintf (of, "%ld: %s%d (%s)\n", (long int) pthread_self (),
740 prefix, sig, strsignal (sig));
741 }
742 }
743
744 if (cnt == 0)
745 fprintf (of, "%ld: %s<empty signal set>\n", (long int) pthread_self (),
746 prefix);
747 }
748
749 static int
print_sigmask(FILE * of,const char * msg)750 print_sigmask (FILE *of, const char *msg)
751 {
752 sigset_t sigmask;
753
754 if (msg)
755 fprintf (of, "%s", msg);
756
757 if (pthread_sigmask (SIG_BLOCK, NULL, &sigmask) == -1)
758 return -1;
759
760 print_sigset (of, "\t\t", &sigmask);
761
762 return 0;
763 }
764 #endif
765
766 void
octave_show_sigmask(const char * msg)767 octave_show_sigmask (const char *msg)
768 {
769 #if ! defined (__WIN32__)
770 if (! msg)
771 msg = "signal mask\n";
772
773 print_sigmask (stderr, msg);
774 #else
775 octave_unused_parameter (msg);
776
777 fputs ("no signal mask on Windows systems\n", stderr);
778 #endif
779 }
780