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