GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
sighandlers.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1993-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#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <atomic>
31#include <csignal>
32#include <cstdlib>
33
34#include <iostream>
35#include <new>
36
37#if defined (OCTAVE_USE_WINDOWS_API)
38# define WIN32_LEAN_AND_MEAN
39# include <windows.h>
40#endif
41
42#include "child-list.h"
43#include "cmd-edit.h"
44#include "oct-syscalls.h"
45#include "quit.h"
46#include "signal-wrappers.h"
47
48#include "defun.h"
49#include "error.h"
50#include "input.h"
51#include "interpreter-private.h"
52#include "interpreter.h"
53#include "load-save.h"
54#include "octave.h"
55#include "oct-map.h"
56#include "pager.h"
57#include "sighandlers.h"
58#include "sysdep.h"
59#include "utils.h"
60#include "variables.h"
61
63
64// Nonzero means we have already printed a message for this series of
65// SIGPIPES. We assume that the writer will eventually give up.
67
68// TRUE means we can be interrupted.
69std::atomic<bool> can_interrupt{false};
70
71// TRUE means we should try to enter the debugger on SIGINT.
73
74// Allow users to avoid writing octave-workspace for SIGHUP (sent by
75// closing gnome-terminal, for example). Note that this variable has
76// no effect if Vcrash_dumps_octave_core is FALSE.
77static bool Vsighup_dumps_octave_core = true;
78
79// Similar to Vsighup_dumps_octave_core, but for SIGQUIT signal.
80static bool Vsigquit_dumps_octave_core = true;
81
82// Similar to Vsighup_dumps_octave_core, but for SIGTERM signal.
83static bool Vsigterm_dumps_octave_core = true;
84
85// List of signals we have caught since last call to signal_handler.
86static std::atomic<bool> *signals_caught = nullptr;
87
88static void
89my_friendly_exit (int sig, bool save_vars = true)
90{
91 std::cerr << "fatal: caught signal "
93 << " -- stopping myself..." << std::endl;
94
95 if (save_vars)
96 {
98
99 load_save_sys.dump_octave_core ();
100 }
101
103
104 throw exit_exception (1);
105}
106
107// Called from octave_quit () to actually do something about the signals
108// we have caught.
109
110void
112{
113 // The list of signals is relatively short, so we will just go
114 // linearly through the list.
115
116 // Interrupt signals are currently handled separately.
117
118 static int sigint;
119 static const bool have_sigint
120 = octave_get_sig_number ("SIGINT", &sigint);
121
122 static int sigbreak;
123 static const bool have_sigbreak
124 = octave_get_sig_number ("SIGBREAK", &sigbreak);
125
126 // Termination signals.
127
128 static int sighup;
129 static const bool have_sighup
130 = octave_get_sig_number ("SIGHUP", &sighup);
131
132 static int sigquit;
133 static const bool have_sigquit
134 = octave_get_sig_number ("SIGQUIT", &sigquit);
135
136 static int sigterm;
137 static const bool have_sigterm
138 = octave_get_sig_number ("SIGTERM", &sigterm);
139
140 // Alarm signals.
141
142 static int sigalrm;
143 static const bool have_sigalrm
144 = octave_get_sig_number ("SIGALRM", &sigalrm);
145
146 static int sigvtalrm;
147 static const bool have_sigvtalrm
148 = octave_get_sig_number ("SIGVTALRM", &sigvtalrm);
149
150 // I/O signals.
151
152 static int sigio;
153 static const bool have_sigio
154 = octave_get_sig_number ("SIGIO", &sigio);
155
156 static int siglost;
157 static const bool have_siglost
158 = octave_get_sig_number ("SIGLOST", &siglost);
159
160 static int sigpipe;
161 static const bool have_sigpipe
162 = octave_get_sig_number ("SIGPIPE", &sigpipe);
163
164 // Job control signals.
165
166 static int sigchld;
167 static const bool have_sigchld
168 = octave_get_sig_number ("SIGCHLD", &sigchld);
169
170 static int sigcld;
171 static const bool have_sigcld
172 = octave_get_sig_number ("SIGCLD", &sigcld);
173
174 // Resource limit signals.
175
176 static int sigxcpu;
177 static const bool have_sigxcpu
178 = octave_get_sig_number ("SIGXCPU", &sigxcpu);
179
180 static int sigxfsz;
181 static const bool have_sigxfsz
182 = octave_get_sig_number ("SIGXFSZ", &sigxfsz);
183
184 // User signals.
185
186 static int sigusr1;
187 static const bool have_sigusr1
188 = octave_get_sig_number ("SIGUSR1", &sigusr1);
189
190 static int sigusr2;
191 static const bool have_sigusr2
192 = octave_get_sig_number ("SIGUSR2", &sigusr2);
193
195
196 for (int sig = 0; sig < octave_num_signals (); sig++)
197 {
198 bool expected = true;
199
200 if (signals_caught[sig].compare_exchange_strong (expected, false))
201 {
202 if ((have_sigchld && sig == sigchld)
203 || (have_sigcld && sig == sigcld))
204 {
205 // FIXME: should we block or ignore?
206 interrupt_handler saved_interrupt_handler = ignore_interrupts ();
207
208 void *context = octave_block_child ();
209
210 kids.wait ();
211
212 set_interrupt_handler (saved_interrupt_handler);
213
214 octave_unblock_child (context);
215
216 kids.reap ();
217 }
218 else if (have_sigpipe && sig == sigpipe)
219 {
220 std::cerr << "warning: broken pipe" << std::endl;
221
222 // Don't loop forever on account of this.
223 // FIXME: is this really needed? Does it do anything
224 // useful now?
225
226 if (pipe_handler_error_count++ > 100
229 }
230 else if (have_sighup && sig == sighup)
231 my_friendly_exit (sighup, Vsighup_dumps_octave_core);
232 else if (have_sigquit && sig == sigquit)
233 my_friendly_exit (sigquit, Vsigquit_dumps_octave_core);
234 else if (have_sigterm && sig == sigterm)
235 my_friendly_exit (sigterm, Vsigterm_dumps_octave_core);
236 else if ((have_sigalrm && sig == sigalrm)
237 || (have_sigvtalrm && sig == sigvtalrm)
238 || (have_sigio && sig == sigio)
239 || (have_siglost && sig == siglost)
240 || (have_sigxcpu && sig == sigxcpu)
241 || (have_sigxfsz && sig == sigxfsz)
242 || (have_sigusr1 && sig == sigusr1)
243 || (have_sigusr2 && sig == sigusr2))
244 std::cerr << "warning: ignoring signal: "
246 << std::endl;
247 else if ((have_sigint && sig == sigint)
248 || (have_sigbreak && sig == sigbreak))
249 ; // Handled separately; do nothing.
250 else
251 std::cerr << "warning: ignoring unexpected signal: "
253 << std::endl;
254 }
255 }
256}
257
259set_signal_handler (int sig, sig_handler *handler, bool restart_syscalls)
260{
261 return octave_set_signal_handler_internal (sig, handler, restart_syscalls);
262}
263
265set_signal_handler (const char *signame, sig_handler *handler,
266 bool restart_syscalls)
267{
268 return octave_set_signal_handler_by_name (signame, handler,
269 restart_syscalls);
270}
271
272static void
273generic_sig_handler (int sig)
274{
275 // FIXME: this function may execute in a separate signal handler or
276 // signal watcher thread so it should probably be more careful about
277 // how it accesses global objects.
278
280
281 signals_caught[sig] = true;
282
283 static int sigint;
284 static const bool have_sigint
285 = octave_get_sig_number ("SIGINT", &sigint);
286
287 static int sigbreak;
288 static const bool have_sigbreak
289 = octave_get_sig_number ("SIGBREAK", &sigbreak);
290
291 if ((have_sigint && sig == sigint)
292 || (have_sigbreak && sig == sigbreak))
293 {
294 if (! octave_initialized)
295 exit (1);
296
297 if (can_interrupt)
298 {
301 }
302 }
303}
304
305static void
306deadly_sig_handler (int sig)
307{
308 std::cerr << "fatal: caught signal "
310 << " -- stopping myself..." << std::endl;
311
313
315}
316
317static void
318fpe_sig_handler (int)
319{
320 // FIXME: is there something better we can do?
321
322 std::cerr << "warning: floating point exception" << std::endl;
323}
324
327{
328 interrupt_handler retval;
329
330 retval.int_handler = set_signal_handler ("SIGINT", generic_sig_handler);
331 retval.brk_handler = set_signal_handler ("SIGBREAK", generic_sig_handler);
332
333 return retval;
334}
335
338{
339 interrupt_handler retval;
340
341 retval.int_handler = set_signal_handler ("SIGINT", SIG_IGN);
342 retval.brk_handler = set_signal_handler ("SIGBREAK", SIG_IGN);
343
344 return retval;
345}
346
348set_interrupt_handler (const interrupt_handler& h, bool restart_syscalls)
349{
350 interrupt_handler retval;
351
352 retval.int_handler = set_signal_handler ("SIGINT", h.int_handler,
353 restart_syscalls);
354
355 retval.brk_handler = set_signal_handler ("SIGBREAK", h.brk_handler,
356 restart_syscalls);
357
358 return retval;
359}
360
361// Install all the handlers for the signals we might care about.
362
363void
365{
366 if (! signals_caught)
367 signals_caught = new std::atomic<bool> [octave_num_signals ()];
368
369 for (int i = 0; i < octave_num_signals (); i++)
370 signals_caught[i] = false;
371
372 // Interrupt signals.
373
375
376 // Program Error signals. These are most likely unrecoverable for
377 // us.
378
379 set_signal_handler ("SIGABRT", deadly_sig_handler);
380 set_signal_handler ("SIGBUS", deadly_sig_handler);
381 set_signal_handler ("SIGEMT", deadly_sig_handler);
382 set_signal_handler ("SIGILL", deadly_sig_handler);
383 // SIGIOT is normally another name for SIGABRT.
384 set_signal_handler ("SIGIOT", deadly_sig_handler);
385 set_signal_handler ("SIGSEGV", deadly_sig_handler);
386 set_signal_handler ("SIGSYS", deadly_sig_handler);
387 set_signal_handler ("SIGTRAP", deadly_sig_handler);
388
389 // Handle SIGFPE separately.
390
391 set_signal_handler ("SIGFPE", fpe_sig_handler);
392
393 // Handle other signals for which the default action is to terminate
394 // the program.
395
396 // Termination signals.
397
398 set_signal_handler ("SIGHUP", generic_sig_handler);
399 set_signal_handler ("SIGQUIT", generic_sig_handler);
400 set_signal_handler ("SIGTERM", generic_sig_handler);
401
402 // Alarm signals.
403
404 set_signal_handler ("SIGALRM", generic_sig_handler);
405 set_signal_handler ("SIGVTALRM", generic_sig_handler);
406
407 // I/O signals.
408
409 set_signal_handler ("SIGLOST", generic_sig_handler);
410 set_signal_handler ("SIGPIPE", generic_sig_handler);
411
412 // Job control signals. We only recognize signals about child
413 // processes.
414
415 set_signal_handler ("SIGCHLD", generic_sig_handler);
416 set_signal_handler ("SIGCLD", generic_sig_handler);
417
418 // Resource limit signals.
419
420 // FIXME: does it really make sense to try to handle the CPU limit
421 // signal?
422
423 set_signal_handler ("SIGXCPU", generic_sig_handler);
424 set_signal_handler ("SIGXFSZ", generic_sig_handler);
425
426 // User signals.
427
428 set_signal_handler ("SIGUSR1", generic_sig_handler);
429 set_signal_handler ("SIGUSR2", generic_sig_handler);
430
431 // This does nothing on Windows systems.
432 octave_create_interrupt_watcher_thread (generic_sig_handler);
433}
434
435static void
436set_sig_struct_field (octave_scalar_map& m, const char *signame)
437{
438 int signum;
439
440 // The names in the struct do not include the leading "SIG" prefix.
441
442 if (octave_get_sig_number (signame, &signum))
443 m.assign (&signame[3], signum);
444}
445
447make_sig_struct ()
448{
450
451 set_sig_struct_field (m, "SIGABRT");
452 set_sig_struct_field (m, "SIGALRM");
453 set_sig_struct_field (m, "SIGBUS");
454 set_sig_struct_field (m, "SIGCHLD");
455 set_sig_struct_field (m, "SIGCLD");
456 set_sig_struct_field (m, "SIGCONT");
457 set_sig_struct_field (m, "SIGEMT");
458 set_sig_struct_field (m, "SIGFPE");
459 set_sig_struct_field (m, "SIGHUP");
460 set_sig_struct_field (m, "SIGILL");
461 set_sig_struct_field (m, "SIGINFO");
462 set_sig_struct_field (m, "SIGINT");
463 set_sig_struct_field (m, "SIGIO");
464 set_sig_struct_field (m, "SIGIOT");
465 set_sig_struct_field (m, "SIGKILL");
466 set_sig_struct_field (m, "SIGLOST");
467 set_sig_struct_field (m, "SIGPIPE");
468 set_sig_struct_field (m, "SIGPOLL");
469 set_sig_struct_field (m, "SIGPROF");
470 set_sig_struct_field (m, "SIGPWR");
471 set_sig_struct_field (m, "SIGQUIT");
472 set_sig_struct_field (m, "SIGSEGV");
473 set_sig_struct_field (m, "SIGSTKFLT");
474 set_sig_struct_field (m, "SIGSTOP");
475 set_sig_struct_field (m, "SIGSYS");
476 set_sig_struct_field (m, "SIGTERM");
477 set_sig_struct_field (m, "SIGTRAP");
478 set_sig_struct_field (m, "SIGTSTP");
479 set_sig_struct_field (m, "SIGTTIN");
480 set_sig_struct_field (m, "SIGTTOU");
481 set_sig_struct_field (m, "SIGUNUSED");
482 set_sig_struct_field (m, "SIGURG");
483 set_sig_struct_field (m, "SIGUSR1");
484 set_sig_struct_field (m, "SIGUSR2");
485 set_sig_struct_field (m, "SIGVTALRM");
486 set_sig_struct_field (m, "SIGWINCH");
487 set_sig_struct_field (m, "SIGXCPU");
488 set_sig_struct_field (m, "SIGXFSZ");
489
490 return m;
491}
492
493DEFUN (SIG, args, ,
494 doc: /* -*- texinfo -*-
495@deftypefn {} {@var{S} =} SIG ()
496Return a structure containing Unix signal names and their defined values.
497@end deftypefn */)
498{
499 if (args.length () != 0)
500 print_usage ();
501
502 static octave_scalar_map m = make_sig_struct ();
503
504 return ovl (m);
505}
506
507/*
508%!assert (isstruct (SIG ()))
509%!assert (! isempty (SIG ()))
510
511%!error SIG (1)
512*/
513
514DEFUN (debug_on_interrupt, args, nargout,
515 doc: /* -*- texinfo -*-
516@deftypefn {} {@var{val} =} debug_on_interrupt ()
517@deftypefnx {} {@var{old_val} =} debug_on_interrupt (@var{new_val})
518@deftypefnx {} {@var{old_val} =} debug_on_interrupt (@var{new_val}, "local")
519Query or set the internal variable that controls whether Octave will try
520to enter debugging mode when it receives an interrupt signal (typically
521generated with @kbd{C-c}).
522
523If a second interrupt signal is received before reaching the debugging mode,
524a normal interrupt will occur.
525
526When called from inside a function with the @qcode{"local"} option, the
527variable is changed locally for the function and any subroutines it calls.
528The original variable value is restored when exiting the function.
529@seealso{debug_on_error, debug_on_warning}
530@end deftypefn */)
531{
532 return set_internal_variable (Vdebug_on_interrupt, args, nargout,
533 "debug_on_interrupt");
534}
535
536/*
537%!test
538%! orig_val = debug_on_interrupt ();
539%! old_val = debug_on_interrupt (! orig_val);
540%! assert (orig_val, old_val);
541%! assert (debug_on_interrupt (), ! orig_val);
542%! debug_on_interrupt (orig_val);
543%! assert (debug_on_interrupt (), orig_val);
544
545%!error debug_on_interrupt (1, 2)
546*/
547
548DEFUN (sighup_dumps_octave_core, args, nargout,
549 doc: /* -*- texinfo -*-
550@deftypefn {} {@var{val} =} sighup_dumps_octave_core ()
551@deftypefnx {} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val})
552@deftypefnx {} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val}, "local")
553Query or set the internal variable that controls whether Octave tries
554to save all current variables to the file @file{octave-workspace} if it
555receives a hangup signal.
556
557When called from inside a function with the @qcode{"local"} option, the
558variable is changed locally for the function and any subroutines it calls.
559The original variable value is restored when exiting the function.
560@end deftypefn */)
561{
562 return set_internal_variable (Vsighup_dumps_octave_core,
563 args, nargout,
564 "sighup_dumps_octave_core");
565}
566
567/*
568%!test
569%! orig_val = sighup_dumps_octave_core ();
570%! old_val = sighup_dumps_octave_core (! orig_val);
571%! assert (orig_val, old_val);
572%! assert (sighup_dumps_octave_core (), ! orig_val);
573%! sighup_dumps_octave_core (orig_val);
574%! assert (sighup_dumps_octave_core (), orig_val);
575
576%!error sighup_dumps_octave_core (1, 2)
577*/
578
579DEFUN (sigquit_dumps_octave_core, args, nargout,
580 doc: /* -*- texinfo -*-
581@deftypefn {} {@var{val} =} sigquit_dumps_octave_core ()
582@deftypefnx {} {@var{old_val} =} sigquit_dumps_octave_core (@var{new_val})
583@deftypefnx {} {@var{old_val} =} sigquit_dumps_octave_core (@var{new_val}, "local")
584Query or set the internal variable that controls whether Octave tries
585to save all current variables to the file @file{octave-workspace} if it
586receives a quit signal.
587
588When called from inside a function with the @qcode{"local"} option, the
589variable is changed locally for the function and any subroutines it calls.
590The original variable value is restored when exiting the function.
591@end deftypefn */)
592{
593 return set_internal_variable (Vsigquit_dumps_octave_core,
594 args, nargout,
595 "sigquit_dumps_octave_core");
596}
597
598/*
599%!test
600%! orig_val = sigquit_dumps_octave_core ();
601%! old_val = sigquit_dumps_octave_core (! orig_val);
602%! assert (orig_val, old_val);
603%! assert (sigquit_dumps_octave_core (), ! orig_val);
604%! sigquit_dumps_octave_core (orig_val);
605%! assert (sigquit_dumps_octave_core (), orig_val);
606
607%!error sigquit_dumps_octave_core (1, 2)
608*/
609
610DEFUN (sigterm_dumps_octave_core, args, nargout,
611 doc: /* -*- texinfo -*-
612@deftypefn {} {@var{val} =} sigterm_dumps_octave_core ()
613@deftypefnx {} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val})
614@deftypefnx {} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val}, "local")
615Query or set the internal variable that controls whether Octave tries
616to save all current variables to the file @file{octave-workspace} if it
617receives a terminate signal.
618
619When called from inside a function with the @qcode{"local"} option, the
620variable is changed locally for the function and any subroutines it calls.
621The original variable value is restored when exiting the function.
622@end deftypefn */)
623{
624 return set_internal_variable (Vsigterm_dumps_octave_core,
625 args, nargout,
626 "sigterm_dumps_octave_core");
627}
628
629/*
630%!test
631%! orig_val = sigterm_dumps_octave_core ();
632%! old_val = sigterm_dumps_octave_core (! orig_val);
633%! assert (orig_val, old_val);
634%! assert (sigterm_dumps_octave_core (), ! orig_val);
635%! sigterm_dumps_octave_core (orig_val);
636%! assert (sigterm_dumps_octave_core (), orig_val);
637
638%!error sigterm_dumps_octave_core (1, 2)
639*/
640
641OCTAVE_END_NAMESPACE(octave)
bool wait()
Definition child-list.cc:76
void reap()
Definition child-list.cc:47
void dump_octave_core()
Definition load-save.cc:734
void assign(const std::string &k, const octave_value &val)
Definition oct-map.h:230
void octave_create_interrupt_watcher_thread(octave_sig_handler *handler)
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition defun.h:56
child_list & __get_child_list__()
load_save_system & __get_load_save_system__()
std::atomic< bool > octave_initialized
double signum(double x)
Definition lo-mappers.h:229
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
std::atomic< bool > octave_signal_caught
Definition quit.cc:41
std::atomic< sig_atomic_t > octave_interrupt_state
Definition quit.cc:39
interrupt_handler ignore_interrupts()
void respond_to_pending_signals()
bool Vdebug_on_interrupt
int pipe_handler_error_count
sig_handler * set_signal_handler(int sig, sig_handler *handler, bool restart_syscalls)
interrupt_handler set_interrupt_handler(const interrupt_handler &h, bool restart_syscalls)
std::atomic< bool > can_interrupt
interrupt_handler catch_interrupts()
void install_signal_handlers()
void sig_handler(int)
Definition sighandlers.h:48
void * octave_block_child(void)
int octave_num_signals(void)
void octave_unblock_child(void *context_arg)
bool octave_get_sig_number(const char *signame, int *signum)
char * octave_strsignal_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)
octave_sig_handler * octave_set_default_signal_handler(int sig)
int octave_raise_wrapper(int signum)
sig_handler * int_handler
Definition sighandlers.h:52
sig_handler * brk_handler
Definition sighandlers.h:53
void sysdep_cleanup()
Definition sysdep.cc:456
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition variables.cc:583