GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
signal-wrappers.c
Go to the documentation of this file.
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
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 *
65 {
66  return strsignal (signum);
67 }
68 
69 bool
71 {
72 #if defined (HAVE_KILL)
73  return true;
74 #else
75  return false;
76 #endif
77 }
78 
79 bool
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 
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 
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 
397 {
398  return octave_set_signal_handler_internal (sig, SIG_DFL, true);
399 }
400 
403 {
404  return octave_set_signal_handler_by_name (signame, SIG_DFL, true);
405 }
406 
407 int
409 {
410  return NSIG;
411 }
412 
413 typedef struct
414 {
415  sigset_t nvar;
416  sigset_t ovar;
417 } sigset_info;
418 
419 void *
421 {
422 #if defined (SIGCHLD) || defined (SIGCLD)
423 
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
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
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
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
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
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
519 octave_block_signal_by_name (const char *signame)
520 {
521  block_or_unblock_signal_by_name (SIG_BLOCK, signame);
522 }
523 
524 void
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
542 {
543  sigprocmask (0, 0, &octave_signal_mask);
544 }
545 
546 void
548 {
549  sigprocmask (SIG_SETMASK, &octave_signal_mask, 0);
550 }
551 
552 void *
554 {
555  return malloc (sizeof (sigset_t));
556 }
557 
558 void
560 {
561  free (mask);
562 }
563 
564 void
566 {
567  sigprocmask (0, 0, mask);
568 }
569 
570 void
572 {
573  sigprocmask (SIG_SETMASK, (sigset_t *) mask, 0);
574 }
575 
576 #if ! defined (__WIN32__)
577 static const sigset_t *
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
663 {
664 #if ! defined (__WIN32__) || defined (__CYGWIN__)
665  pthread_sigmask (SIG_BLOCK, octave_async_signals (), 0);
666 #endif
667 }
668 
669 void
671 {
672 #if ! defined (__WIN32__) || defined (__CYGWIN__)
673  pthread_sigmask (SIG_UNBLOCK, octave_async_signals (), 0);
674 #endif
675 }
676 
677 int
679 {
680  return raise (signum);
681 }
682 
683 #if ! defined (__WIN32__)
684 static void *
685 signal_watcher (void *arg)
686 {
687  octave_sig_handler *handler = (octave_sig_handler *) arg;
688 
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
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
722 
723  octave_unused_parameter (handler);
724 #endif
725 }
726 
727 #if ! defined (__WIN32__)
728 static void
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
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
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 }
double signum(double x)
Definition: lo-mappers.h:222
bool strcmp(const T &str_a, const T &str_b)
True if strings are the same.
Definition: oct-string.cc:122
int kill(pid_t pid, int sig)
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:80
void * malloc(unsigned)
void free(void *)
void octave_save_signal_mask(void)
void octave_block_interrupt_signal(void)
void octave_create_interrupt_watcher_thread(octave_sig_handler *handler)
static void print_sigset(FILE *of, const char *prefix, const sigset_t *sigset)
octave_sig_handler * octave_set_default_signal_handler(int sig)
int octave_num_signals(void)
void octave_block_signal_by_name(const char *signame)
void * octave_block_child(void)
void octave_unblock_signal_by_name(const char *signame)
char * octave_strsignal_wrapper(int signum)
void octave_show_sigmask(const char *msg)
void octave_set_signal_mask(void *mask)
void octave_free_signal_mask(void *mask)
void octave_unblock_child(void *context_arg)
bool octave_get_sig_number(const char *signame, int *signum)
void octave_get_signal_mask(void *mask)
static void block_or_unblock_signal_by_name(int how, const char *signame)
int octave_kill_wrapper(pid_t pid, int signum)
octave_sig_handler * octave_set_default_signal_handler_by_name(const char *signame)
static void block_or_unblock_signal(int how, int sig)
void octave_unblock_async_signals(void)
static sigset_t octave_signal_mask
void octave_restore_signal_mask(void)
void octave_unblock_interrupt_signal(void)
void octave_block_async_signals(void)
static void * signal_watcher(void *arg)
bool octave_have_kill(void)
static const sigset_t * octave_async_signals(void)
int octave_raise_wrapper(int signum)
static int print_sigmask(FILE *of, const char *msg)
octave_sig_handler * octave_set_signal_handler_by_name(const char *signame, octave_sig_handler *handler, bool restart_syscalls)
octave_sig_handler * octave_set_signal_handler_internal(int sig, octave_sig_handler *handler, bool restart_syscalls)
void * octave_alloc_signal_mask(void)
void octave_sig_handler(int)