GNU Octave 7.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-2022 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
49int
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
66char *
68{
69 return strsignal (signum);
70}
71
72bool
74{
75#if defined (HAVE_KILL)
76 return true;
77#else
78 return false;
79#endif
80}
81
82bool
83octave_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
410int
412{
413 return NSIG;
414}
415
416typedef struct
417{
418 sigset_t nvar;
419 sigset_t ovar;
421
422void *
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
451void
452octave_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
464static void
465block_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
492void
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
502void
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
512static void
513block_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
521void
522octave_block_signal_by_name (const char *signame)
523{
524 block_or_unblock_signal_by_name (SIG_BLOCK, signame);
525}
526
527void
528octave_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
541static sigset_t octave_signal_mask;
542
543void
545{
546 sigprocmask (0, 0, &octave_signal_mask);
547}
548
549void
551{
552 sigprocmask (SIG_SETMASK, &octave_signal_mask, 0);
553}
554
555void *
557{
558 return malloc (sizeof (sigset_t));
559}
560
561void
563{
564 free (mask);
565}
566
567void
569{
570 sigprocmask (0, 0, mask);
571}
572
573void
575{
576 sigprocmask (SIG_SETMASK, (sigset_t *) mask, 0);
577}
578
579#if ! defined (__WIN32__)
580static const sigset_t *
582{
583 static bool initialized = false;
584 static sigset_t sigmask;
585
586 if (! initialized)
587 {
588 sigemptyset (&sigmask);
589
590 // The signals listed here should match the list of signals that
591 // we handle in the signal handler thread.
592
593 // Interrupt signals.
594
595#if defined (SIGINT)
596 sigaddset (&sigmask, SIGINT);
597#endif
598
599#if defined (SIGBREAK)
600 sigaddset (&sigmask, SIGBREAK);
601#endif
602
603 // Termination signals.
604
605#if defined (SIGHUP)
606 sigaddset (&sigmask, SIGHUP);
607#endif
608
609#if defined (SIGQUIT)
610 sigaddset (&sigmask, SIGQUIT);
611#endif
612
613#if defined (SIGTERM)
614 sigaddset (&sigmask, SIGTERM);
615#endif
616
617 // Alarm signals.
618
619#if defined (SIGALRM)
620 sigaddset (&sigmask, SIGALRM);
621#endif
622
623#if defined (SIGVTALRM)
624 sigaddset (&sigmask, SIGVTALRM);
625#endif
626
627 // I/O signals.
628
629#if defined (SIGLOST)
630 sigaddset (&sigmask, SIGLOST);
631#endif
632
633#if defined (SIGPIPE)
634 sigaddset (&sigmask, SIGPIPE);
635#endif
636
637 // Job control signals.
638
639#if defined (SIGCHLD)
640 sigaddset (&sigmask, SIGCHLD);
641#endif
642
643#if defined (SIGCLD)
644 sigaddset (&sigmask, SIGCLD);
645#endif
646
647 // Resource limit signals.
648
649#if defined (SIGXCPU)
650 sigaddset (&sigmask, SIGXCPU);
651#endif
652
653#if defined (SIGXFSZ)
654 sigaddset (&sigmask, SIGXFSZ);
655#endif
656
657 initialized = true;
658 }
659
660 return &sigmask;
661}
662#endif
663
664void
666{
667#if ! defined (__WIN32__) || defined (__CYGWIN__)
668 pthread_sigmask (SIG_BLOCK, octave_async_signals (), 0);
669#endif
670}
671
672void
674{
675#if ! defined (__WIN32__) || defined (__CYGWIN__)
676 pthread_sigmask (SIG_UNBLOCK, octave_async_signals (), 0);
677#endif
678}
679
680int
682{
683 return raise (signum);
684}
685
686#if ! defined (__WIN32__)
687static void *
688signal_watcher (void *arg)
689{
690 octave_sig_handler *handler = (octave_sig_handler *) arg;
691
693
694 const sigset_t *async_signals = octave_async_signals ();
695
696 while (1)
697 {
698 int sig_caught;
699
700 if (sigwait (async_signals, &sig_caught))
701 {
702 // FIXME: what else should we do?
703 abort ();
704 }
705
706 // Let handler have complete control over what to do.
707 (*handler) (sig_caught);
708 }
709}
710#endif
711
712void
714{
715#if ! defined (__WIN32__)
716 pthread_t sighandler_thread_id;
717
718 if (pthread_create (&sighandler_thread_id, 0, signal_watcher, handler))
719 {
720 // FIXME: what else should we do?
721 abort ();
722 }
723#else
725
726 octave_unused_parameter (handler);
727#endif
728}
729
730#if ! defined (__WIN32__)
731static void
732print_sigset (FILE *of, const char *prefix, const sigset_t *sigset)
733{
734 int sig;
735 int cnt = 0;
736
737 for (sig = 1; sig < NSIG; sig++)
738 {
739 if (sigismember (sigset, sig))
740 {
741 cnt++;
742 fprintf (of, "%ld: %s%d (%s)\n", (long int) pthread_self (),
743 prefix, sig, strsignal (sig));
744 }
745 }
746
747 if (cnt == 0)
748 fprintf (of, "%ld: %s<empty signal set>\n", (long int) pthread_self (),
749 prefix);
750}
751
752static int
753print_sigmask (FILE *of, const char *msg)
754{
755 sigset_t sigmask;
756
757 if (msg)
758 fprintf (of, "%s", msg);
759
760 if (pthread_sigmask (SIG_BLOCK, NULL, &sigmask) == -1)
761 return -1;
762
763 print_sigset (of, "\t\t", &sigmask);
764
765 return 0;
766}
767#endif
768
769void
770octave_show_sigmask (const char *msg)
771{
772#if ! defined (__WIN32__)
773 if (! msg)
774 msg = "signal mask\n";
775
776 print_sigmask (stderr, msg);
777#else
778 octave_unused_parameter (msg);
779
780 fputs ("no signal mask on Windows systems\n", stderr);
781#endif
782}
double signum(double x)
Definition: lo-mappers.h:229
OCTAVE_API bool strcmp(const T &str_a, const T &str_b)
True if strings are the same.
int kill(pid_t pid, int sig)
void * malloc(unsigned)
void free(void *)
static const sigset_t * octave_async_signals(void)
void octave_save_signal_mask(void)
void * octave_block_child(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)
int octave_num_signals(void)
void octave_block_signal_by_name(const char *signame)
void octave_unblock_signal_by_name(const char *signame)
void octave_show_sigmask(const char *msg)
void octave_set_signal_mask(void *mask)
static void * signal_watcher(void *arg)
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)
char * octave_strsignal_wrapper(int signum)
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
octave_sig_handler * octave_set_signal_handler_by_name(const char *signame, octave_sig_handler *handler, bool restart_syscalls)
void octave_restore_signal_mask(void)
void octave_unblock_interrupt_signal(void)
void octave_block_async_signals(void)
octave_sig_handler * octave_set_signal_handler_internal(int sig, octave_sig_handler *handler, bool restart_syscalls)
bool octave_have_kill(void)
octave_sig_handler * octave_set_default_signal_handler(int sig)
int octave_raise_wrapper(int signum)
static int print_sigmask(FILE *of, const char *msg)
void * octave_alloc_signal_mask(void)
void octave_sig_handler(int)