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