GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
signal-wrappers.c
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2016-2025 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;
420} sigset_info;
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
579int
581{
582 return raise (signum);
583}
584
585#if ! defined (__WIN32__)
586static void
587print_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
607static int
608print_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
624void
625octave_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_child(void)
void octave_block_interrupt_signal(void)
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)
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)
int octave_kill_wrapper(pid_t pid, int signum)
octave_sig_handler * octave_set_default_signal_handler_by_name(const char *signame)
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)
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)
void * octave_alloc_signal_mask(void)
void octave_sig_handler(int)