GNU Octave  9.1.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-2024 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 #elif defined (HAVE_RAISE)
55  octave_unused_parameter (pid);
56 
57  return raise (signum);
58 #else
59  octave_unused_parameter (pid);
60  octave_unused_parameter (signum);
61 
62  return -1;
63 #endif
64 }
65 
66 char *
68 {
69  return strsignal (signum);
70 }
71 
72 bool
74 {
75 #if defined (HAVE_KILL)
76  return true;
77 #else
78  return false;
79 #endif
80 }
81 
82 bool
83 octave_get_sig_number (const char *signame, int *signum)
84 {
85  *signum = -1;
86 
87  // FIXME: this should probably use a perfect hash function.
88 
89  if (! strcmp (signame, "SIGINT"))
90  {
91 #if defined (SIGINT)
92  *signum = SIGINT;
93  return true;
94 #endif
95  }
96  else if (! strcmp (signame, "SIGBREAK"))
97  {
98 #if defined (SIGBREAK)
99  *signum = SIGBREAK;
100  return true;
101 #endif
102  }
103  else if (! strcmp (signame, "SIGABRT"))
104  {
105 #if defined (SIGABRT)
106  *signum = SIGABRT;
107  return true;
108 #endif
109  }
110  else if (! strcmp (signame, "SIGALRM"))
111  {
112 #if defined (SIGALRM)
113  *signum = SIGALRM;
114  return true;
115 #endif
116  }
117  else if (! strcmp (signame, "SIGBUS"))
118  {
119 #if defined (SIGBUS)
120  *signum = SIGBUS;
121  return true;
122 #endif
123  }
124  else if (! strcmp (signame, "SIGCHLD"))
125  {
126 #if defined (SIGCHLD)
127  *signum = SIGCHLD;
128  return true;
129 #endif
130  }
131  else if (! strcmp (signame, "SIGCLD"))
132  {
133 #if defined (SIGCLD)
134  *signum = SIGCLD;
135  return true;
136 #endif
137  }
138  else if (! strcmp (signame, "SIGCONT"))
139  {
140 #if defined (SIGCONT)
141  *signum = SIGCONT;
142  return true;
143 #endif
144  }
145  else if (! strcmp (signame, "SIGEMT"))
146  {
147 #if defined (SIGEMT)
148  *signum = SIGEMT;
149  return true;
150 #endif
151  }
152  else if (! strcmp (signame, "SIGFPE"))
153  {
154 #if defined (SIGFPE)
155  *signum = SIGFPE;
156  return true;
157 #endif
158  }
159  else if (! strcmp (signame, "SIGHUP"))
160  {
161 #if defined (SIGHUP)
162  *signum = SIGHUP;
163  return true;
164 #endif
165  }
166  else if (! strcmp (signame, "SIGILL"))
167  {
168 #if defined (SIGILL)
169  *signum = SIGILL;
170  return true;
171 #endif
172  }
173  else if (! strcmp (signame, "SIGINFO"))
174  {
175 #if defined (SIGINFO)
176  *signum = SIGINFO;
177  return true;
178 #endif
179  }
180  else if (! strcmp (signame, "SIGIOT"))
181  {
182 #if defined (SIGIOT)
183  *signum = SIGIOT;
184  return true;
185 #endif
186  }
187  else if (! strcmp (signame, "SIGKILL"))
188  {
189 #if defined (SIGKILL)
190  *signum = SIGKILL;
191  return true;
192 #endif
193  }
194  else if (! strcmp (signame, "SIGLOST"))
195  {
196 #if defined (SIGLOST)
197  *signum = SIGLOST;
198  return true;
199 #endif
200  }
201  else if (! strcmp (signame, "SIGPIPE"))
202  {
203 #if defined (SIGPIPE)
204  *signum = SIGPIPE;
205  return true;
206 #endif
207  }
208  else if (! strcmp (signame, "SIGPOLL"))
209  {
210 #if defined (SIGPOLL)
211  *signum = SIGPOLL;
212  return true;
213 #endif
214  }
215  else if (! strcmp (signame, "SIGPROF"))
216  {
217 #if defined (SIGPROF)
218  *signum = SIGPROF;
219  return true;
220 #endif
221  }
222  else if (! strcmp (signame, "SIGPWR"))
223  {
224 #if defined (SIGPWR)
225  *signum = SIGPWR;
226  return true;
227 #endif
228  }
229  else if (! strcmp (signame, "SIGQUIT"))
230  {
231 #if defined (SIGQUIT)
232  *signum = SIGQUIT;
233  return true;
234 #endif
235  }
236  else if (! strcmp (signame, "SIGSEGV"))
237  {
238 #if defined (SIGSEGV)
239  *signum = SIGSEGV;
240  return true;
241 #endif
242  }
243  else if (! strcmp (signame, "SIGSTOP"))
244  {
245 #if defined (SIGSTOP)
246  *signum = SIGSTOP;
247  return true;
248 #endif
249  }
250  else if (! strcmp (signame, "SIGSYS"))
251  {
252 #if defined (SIGSYS)
253  *signum = SIGSYS;
254  return true;
255 #endif
256  }
257  else if (! strcmp (signame, "SIGTERM"))
258  {
259 #if defined (SIGTERM)
260  *signum = SIGTERM;
261  return true;
262 #endif
263  }
264  else if (! strcmp (signame, "SIGTRAP"))
265  {
266 #if defined (SIGTRAP)
267  *signum = SIGTRAP;
268  return true;
269 #endif
270  }
271  else if (! strcmp (signame, "SIGTSTP"))
272  {
273 #if defined (SIGTSTP)
274  *signum = SIGTSTP;
275  return true;
276 #endif
277  }
278  else if (! strcmp (signame, "SIGTTIN"))
279  {
280 #if defined (SIGTTIN)
281  *signum = SIGTTIN;
282  return true;
283 #endif
284  }
285  else if (! strcmp (signame, "SIGTTOU"))
286  {
287 #if defined (SIGTTOU)
288  *signum = SIGTTOU;
289  return true;
290 #endif
291  }
292  else if (! strcmp (signame, "SIGURG"))
293  {
294 #if defined (SIGURG)
295  *signum = SIGURG;
296  return true;
297 #endif
298  }
299  else if (! strcmp (signame, "SIGUSR1"))
300  {
301 #if defined (SIGUSR1)
302  *signum = SIGUSR1;
303  return true;
304 #endif
305  }
306  else if (! strcmp (signame, "SIGUSR2"))
307  {
308 #if defined (SIGUSR2)
309  *signum = SIGUSR2;
310  return true;
311 #endif
312  }
313  else if (! strcmp (signame, "SIGVTALRM"))
314  {
315 #if defined (SIGVTALRM)
316  *signum = SIGVTALRM;
317  return true;
318 #endif
319  }
320  else if (! strcmp (signame, "SIGIO"))
321  {
322 #if defined (SIGIO)
323  *signum = SIGIO;
324  return true;
325 #endif
326  }
327  else if (! strcmp (signame, "SIGWINCH"))
328  {
329 #if defined (SIGWINCH)
330  *signum = SIGWINCH;
331  return true;
332 #endif
333  }
334  else if (! strcmp (signame, "SIGXCPU"))
335  {
336 #if defined (SIGXCPU)
337  *signum = SIGXCPU;
338  return true;
339 #endif
340  }
341  else if (! strcmp (signame, "SIGXFSZ"))
342  {
343 #if defined (SIGXFSZ)
344  *signum = SIGXFSZ;
345  return true;
346 #endif
347  }
348 
349  return false;
350 }
351 
354  bool restart_syscalls)
355 {
356  struct sigaction act, oact;
357 
358  act.sa_handler = handler;
359  act.sa_flags = 0;
360 
361 #if defined (SIGALRM)
362  if (sig == SIGALRM)
363  {
364 # if defined (SA_INTERRUPT)
365  act.sa_flags |= SA_INTERRUPT;
366 # endif
367  }
368 #endif
369 #if defined (SA_RESTART)
370 # if defined (SIGALRM)
371  else
372 # endif
373  // FIXME: Do we also need to explicitly disable SA_RESTART?
374  if (restart_syscalls)
375  act.sa_flags |= SA_RESTART;
376 #endif
377 
378  sigemptyset (&act.sa_mask);
379  sigemptyset (&oact.sa_mask);
380 
381  sigaction (sig, &act, &oact);
382 
383  return oact.sa_handler;
384 }
385 
388  octave_sig_handler *handler,
389  bool restart_syscalls)
390 {
391  int sig;
392 
393  return (octave_get_sig_number (signame, &sig)
394  ? octave_set_signal_handler_internal (sig, handler, restart_syscalls)
395  : 0);
396 }
397 
400 {
401  return octave_set_signal_handler_internal (sig, SIG_DFL, true);
402 }
403 
406 {
407  return octave_set_signal_handler_by_name (signame, SIG_DFL, true);
408 }
409 
410 int
412 {
413  return NSIG;
414 }
415 
416 typedef struct
417 {
418  sigset_t nvar;
419  sigset_t ovar;
420 } sigset_info;
421 
422 void *
424 {
425 #if defined (SIGCHLD) || defined (SIGCLD)
426 
427  sigset_info *context = (sigset_info *) malloc (sizeof (sigset_info));
428 
429  if (context)
430  {
431  sigemptyset (&(context->ovar));
432  sigemptyset (&(context->nvar));
433 #if defined (SIGCHLD)
434  sigaddset (&(context->nvar), SIGCHLD);
435 #endif
436 #if defined (SIGCLD)
437  sigaddset (&(context->nvar), SIGCLD);
438 #endif
439  sigprocmask (SIG_BLOCK, &(context->nvar), &(context->ovar));
440  }
441 
442  return context;
443 
444 #else
445 
446  return 0;
447 
448 #endif
449 }
450 
451 void
452 octave_unblock_child (void *context_arg)
453 {
454  if (context_arg)
455  {
456  sigset_info *context = (sigset_info *) context_arg;
457 
458  sigprocmask (SIG_SETMASK, &(context->ovar), 0);
459 
460  free (context);
461  }
462 }
463 
464 static void
465 block_or_unblock_signal (int how, int sig)
466 {
467 #if ! defined (__WIN32__) || defined (__CYGWIN__)
468 
469  // Blocking/unblocking signals at thread level is only supported
470  // on platform with fully compliant POSIX threads. This is not
471  // supported on Win32. Moreover, we have to make sure that SIGINT
472  // handler is not installed before calling AllocConsole: installing
473  // a SIGINT handler internally calls SetConsoleCtrlHandler, which
474  // must be called after AllocConsole to be effective.
475 
476  sigset_t signal_mask;
477 
478  sigemptyset (&signal_mask);
479 
480  sigaddset (&signal_mask, sig);
481 
482  pthread_sigmask (how, &signal_mask, 0);
483 
484 #else
485 
486  octave_unused_parameter (how);
487  octave_unused_parameter (sig);
488 
489 #endif
490 }
491 
492 void
494 {
495  block_or_unblock_signal (SIG_BLOCK, SIGINT);
496 
497 #if defined (SIGBREAK)
498  block_or_unblock_signal (SIG_BLOCK, SIGBREAK);
499 #endif
500 }
501 
502 void
504 {
505  block_or_unblock_signal (SIG_UNBLOCK, SIGINT);
506 
507 #if defined (SIGBREAK)
508  block_or_unblock_signal (SIG_UNBLOCK, SIGBREAK);
509 #endif
510 }
511 
512 static void
513 block_or_unblock_signal_by_name (int how, const char *signame)
514 {
515  int sig;
516 
517  if (octave_get_sig_number (signame, &sig))
518  block_or_unblock_signal (how, sig);
519 }
520 
521 void
522 octave_block_signal_by_name (const char *signame)
523 {
524  block_or_unblock_signal_by_name (SIG_BLOCK, signame);
525 }
526 
527 void
528 octave_unblock_signal_by_name (const char *signame)
529 {
530  block_or_unblock_signal_by_name (SIG_UNBLOCK, signame);
531 }
532 
533 /* Allow us to save the signal mask and then restore it to the most
534  recently saved value. This is necessary when using the POSIX signal
535  handling interface on some systems calling longjmp out of the signal
536  handler to get to the top level on an interrupt doesn't restore the
537  original signal mask. Alternatively, we could use
538  sigsetjmp/siglongjmp, but saving and restoring the signal mask
539  ourselves works ok and seems simpler just now. */
540 
541 static sigset_t octave_signal_mask;
542 
543 void
545 {
546  sigprocmask (0, 0, &octave_signal_mask);
547 }
548 
549 void
551 {
552  sigprocmask (SIG_SETMASK, &octave_signal_mask, 0);
553 }
554 
555 void *
557 {
558  return malloc (sizeof (sigset_t));
559 }
560 
561 void
563 {
564  free (mask);
565 }
566 
567 void
569 {
570  sigprocmask (0, 0, mask);
571 }
572 
573 void
575 {
576  sigprocmask (SIG_SETMASK, (sigset_t *) mask, 0);
577 }
578 
579 int
581 {
582  return raise (signum);
583 }
584 
585 #if ! defined (__WIN32__)
586 static void
587 print_sigset (FILE *of, const char *prefix, const sigset_t *sigset)
588 {
589  int sig;
590  int cnt = 0;
591 
592  for (sig = 1; sig < NSIG; sig++)
593  {
594  if (sigismember (sigset, sig))
595  {
596  cnt++;
597  fprintf (of, "%ld: %s%d (%s)\n", (long int) pthread_self (),
598  prefix, sig, strsignal (sig));
599  }
600  }
601 
602  if (cnt == 0)
603  fprintf (of, "%ld: %s<empty signal set>\n", (long int) pthread_self (),
604  prefix);
605 }
606 
607 static int
608 print_sigmask (FILE *of, const char *msg)
609 {
610  sigset_t sigmask;
611 
612  if (msg)
613  fprintf (of, "%s", msg);
614 
615  if (pthread_sigmask (SIG_BLOCK, NULL, &sigmask) == -1)
616  return -1;
617 
618  print_sigset (of, "\t\t", &sigmask);
619 
620  return 0;
621 }
622 #endif
623 
624 void
625 octave_show_sigmask (const char *msg)
626 {
627 #if ! defined (__WIN32__)
628  if (! msg)
629  msg = "signal mask\n";
630 
631  print_sigmask (stderr, msg);
632 #else
633  octave_unused_parameter (msg);
634 
635  fputs ("no signal mask on Windows systems\n", stderr);
636 #endif
637 }
double signum(double x)
Definition: lo-mappers.h:229
bool strcmp(const T &str_a, const T &str_b)
Octave string utility functions.
int kill(pid_t pid, int sig)
void * malloc(unsigned)
void free(void *)
void octave_save_signal_mask(void)
void octave_block_interrupt_signal(void)
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)
int octave_kill_wrapper(pid_t pid, int signum)
octave_sig_handler * octave_set_default_signal_handler_by_name(const char *signame)
void octave_restore_signal_mask(void)
void octave_unblock_interrupt_signal(void)
bool octave_have_kill(void)
int octave_raise_wrapper(int signum)
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)