GNU Octave  8.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-2023 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 
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 = __get_load_save_system__ ();
97 
98  load_save_sys.dump_octave_core ();
99  }
100 
101  sysdep_cleanup ();
102 
103  throw exit_exception (1);
104 }
105 
106 // Called from octave_quit () to actually do something about the signals
107 // we have caught.
108 
109 void
111 {
112  // The list of signals is relatively short, so we will just go
113  // linearly through the list.
114 
115  // Interrupt signals are currently handled separately.
116 
117  static int sigint;
118  static const bool have_sigint
119  = octave_get_sig_number ("SIGINT", &sigint);
120 
121  static int sigbreak;
122  static const bool have_sigbreak
123  = octave_get_sig_number ("SIGBREAK", &sigbreak);
124 
125  // Termination signals.
126 
127  static int sighup;
128  static const bool have_sighup
129  = octave_get_sig_number ("SIGHUP", &sighup);
130 
131  static int sigquit;
132  static const bool have_sigquit
133  = octave_get_sig_number ("SIGQUIT", &sigquit);
134 
135  static int sigterm;
136  static const bool have_sigterm
137  = octave_get_sig_number ("SIGTERM", &sigterm);
138 
139  // Alarm signals.
140 
141  static int sigalrm;
142  static const bool have_sigalrm
143  = octave_get_sig_number ("SIGALRM", &sigalrm);
144 
145  static int sigvtalrm;
146  static const bool have_sigvtalrm
147  = octave_get_sig_number ("SIGVTALRM", &sigvtalrm);
148 
149  // I/O signals.
150 
151  static int sigio;
152  static const bool have_sigio
153  = octave_get_sig_number ("SIGIO", &sigio);
154 
155  static int siglost;
156  static const bool have_siglost
157  = octave_get_sig_number ("SIGLOST", &siglost);
158 
159  static int sigpipe;
160  static const bool have_sigpipe
161  = octave_get_sig_number ("SIGPIPE", &sigpipe);
162 
163  // Job control signals.
164 
165  static int sigchld;
166  static const bool have_sigchld
167  = octave_get_sig_number ("SIGCHLD", &sigchld);
168 
169  static int sigcld;
170  static const bool have_sigcld
171  = octave_get_sig_number ("SIGCLD", &sigcld);
172 
173  // Resource limit signals.
174 
175  static int sigxcpu;
176  static const bool have_sigxcpu
177  = octave_get_sig_number ("SIGXCPU", &sigxcpu);
178 
179  static int sigxfsz;
180  static const bool have_sigxfsz
181  = octave_get_sig_number ("SIGXFSZ", &sigxfsz);
182 
183  // User signals.
184 
185  static int sigusr1;
186  static const bool have_sigusr1
187  = octave_get_sig_number ("SIGUSR1", &sigusr1);
188 
189  static int sigusr2;
190  static const bool have_sigusr2
191  = octave_get_sig_number ("SIGUSR2", &sigusr2);
192 
193  child_list& kids = __get_child_list__ ();
194 
195  for (int sig = 0; sig < octave_num_signals (); sig++)
196  {
197  if (signals_caught[sig])
198  {
199  signals_caught[sig] = false;
200 
201  if ((have_sigchld && sig == sigchld)
202  || (have_sigcld && sig == sigcld))
203  {
204  // FIXME: should we block or ignore?
205  volatile interrupt_handler saved_interrupt_handler
206  = 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
227  && octave_interrupt_state >= 0)
229  }
230  else if (have_sighup && sig == sighup)
232  else if (have_sigquit && sig == sigquit)
234  else if (have_sigterm && sig == sigterm)
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: "
245  << octave_strsignal_wrapper (sig)
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: "
252  << octave_strsignal_wrapper (sig)
253  << std::endl;
254  }
255  }
256 }
257 
258 sig_handler *
259 set_signal_handler (int sig, sig_handler *handler, bool restart_syscalls)
260 {
261  return octave_set_signal_handler_internal (sig, handler, restart_syscalls);
262 }
263 
264 sig_handler *
265 set_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 
272 static void
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 
305 static void
307 {
308  std::cerr << "fatal: caught signal "
309  << octave_strsignal_wrapper (sig)
310  << " -- stopping myself..." << std::endl;
311 
313 
314  octave_raise_wrapper (sig);
315 }
316 
317 static void
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 
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 
349  bool restart_syscalls)
350 {
351  interrupt_handler retval;
352 
353  retval.int_handler = set_signal_handler ("SIGINT", h.int_handler,
354  restart_syscalls);
355 
356  retval.brk_handler = set_signal_handler ("SIGBREAK", h.brk_handler,
357  restart_syscalls);
358 
359  return retval;
360 }
361 
362 // Install all the handlers for the signals we might care about.
363 
364 void
366 {
367  if (! signals_caught)
368  signals_caught = new bool [octave_num_signals ()];
369 
370  for (int i = 0; i < octave_num_signals (); i++)
371  signals_caught[i] = false;
372 
373  // Interrupt signals.
374 
375  catch_interrupts ();
376 
377  // Program Error signals. These are most likely unrecoverable for
378  // us.
379 
384  // SIGIOT is normally another name for SIGABRT.
389 
390  // Handle SIGFPE separately.
391 
393 
394  // Handle other signals for which the default action is to terminate
395  // the program.
396 
397  // Termination signals.
398 
402 
403  // Alarm signals.
404 
407 
408  // I/O signals.
409 
412 
413  // Job control signals. We only recognize signals about child
414  // processes.
415 
418 
419  // Resource limit signals.
420 
421  // FIXME: does it really make sense to try to handle the CPU limit
422  // signal?
423 
426 
427  // User signals.
428 
431 
432  // This does nothing on Windows systems.
434 }
435 
436 static void
437 set_sig_struct_field (octave_scalar_map& m, const char *signame)
438 {
439  int signum;
440 
441  // The names in the struct do not include the leading "SIG" prefix.
442 
443  if (octave_get_sig_number (signame, &signum))
444  m.assign (&signame[3], signum);
445 }
446 
447 static octave_scalar_map
449 {
451 
452  set_sig_struct_field (m, "SIGABRT");
453  set_sig_struct_field (m, "SIGALRM");
454  set_sig_struct_field (m, "SIGBUS");
455  set_sig_struct_field (m, "SIGCHLD");
456  set_sig_struct_field (m, "SIGCLD");
457  set_sig_struct_field (m, "SIGCONT");
458  set_sig_struct_field (m, "SIGEMT");
459  set_sig_struct_field (m, "SIGFPE");
460  set_sig_struct_field (m, "SIGHUP");
461  set_sig_struct_field (m, "SIGILL");
462  set_sig_struct_field (m, "SIGINFO");
463  set_sig_struct_field (m, "SIGINT");
464  set_sig_struct_field (m, "SIGIO");
465  set_sig_struct_field (m, "SIGIOT");
466  set_sig_struct_field (m, "SIGKILL");
467  set_sig_struct_field (m, "SIGLOST");
468  set_sig_struct_field (m, "SIGPIPE");
469  set_sig_struct_field (m, "SIGPOLL");
470  set_sig_struct_field (m, "SIGPROF");
471  set_sig_struct_field (m, "SIGPWR");
472  set_sig_struct_field (m, "SIGQUIT");
473  set_sig_struct_field (m, "SIGSEGV");
474  set_sig_struct_field (m, "SIGSTKFLT");
475  set_sig_struct_field (m, "SIGSTOP");
476  set_sig_struct_field (m, "SIGSYS");
477  set_sig_struct_field (m, "SIGTERM");
478  set_sig_struct_field (m, "SIGTRAP");
479  set_sig_struct_field (m, "SIGTSTP");
480  set_sig_struct_field (m, "SIGTTIN");
481  set_sig_struct_field (m, "SIGTTOU");
482  set_sig_struct_field (m, "SIGUNUSED");
483  set_sig_struct_field (m, "SIGURG");
484  set_sig_struct_field (m, "SIGUSR1");
485  set_sig_struct_field (m, "SIGUSR2");
486  set_sig_struct_field (m, "SIGVTALRM");
487  set_sig_struct_field (m, "SIGWINCH");
488  set_sig_struct_field (m, "SIGXCPU");
489  set_sig_struct_field (m, "SIGXFSZ");
490 
491  return m;
492 }
493 
494 DEFUN (SIG, args, ,
495  doc: /* -*- texinfo -*-
496 @deftypefn {} {@var{S} =} SIG ()
497 Return a structure containing Unix signal names and their defined values.
498 @end deftypefn */)
499 {
500  if (args.length () != 0)
501  print_usage ();
502 
503  static octave_scalar_map m = make_sig_struct ();
504 
505  return ovl (m);
506 }
507 
508 /*
509 %!assert (isstruct (SIG ()))
510 %!assert (! isempty (SIG ()))
511 
512 %!error SIG (1)
513 */
514 
515 DEFUN (debug_on_interrupt, args, nargout,
516  doc: /* -*- texinfo -*-
517 @deftypefn {} {@var{val} =} debug_on_interrupt ()
518 @deftypefnx {} {@var{old_val} =} debug_on_interrupt (@var{new_val})
519 @deftypefnx {} {@var{old_val} =} debug_on_interrupt (@var{new_val}, "local")
520 Query or set the internal variable that controls whether Octave will try
521 to enter debugging mode when it receives an interrupt signal (typically
522 generated with @kbd{C-c}).
523 
524 If a second interrupt signal is received before reaching the debugging mode,
525 a normal interrupt will occur.
526 
527 When called from inside a function with the @qcode{"local"} option, the
528 variable is changed locally for the function and any subroutines it calls.
529 The original variable value is restored when exiting the function.
530 @seealso{debug_on_error, debug_on_warning}
531 @end deftypefn */)
532 {
533  return set_internal_variable (Vdebug_on_interrupt, args, nargout,
534  "debug_on_interrupt");
535 }
536 
537 /*
538 %!test
539 %! orig_val = debug_on_interrupt ();
540 %! old_val = debug_on_interrupt (! orig_val);
541 %! assert (orig_val, old_val);
542 %! assert (debug_on_interrupt (), ! orig_val);
543 %! debug_on_interrupt (orig_val);
544 %! assert (debug_on_interrupt (), orig_val);
545 
546 %!error debug_on_interrupt (1, 2)
547 */
548 
549 DEFUN (sighup_dumps_octave_core, args, nargout,
550  doc: /* -*- texinfo -*-
551 @deftypefn {} {@var{val} =} sighup_dumps_octave_core ()
552 @deftypefnx {} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val})
553 @deftypefnx {} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val}, "local")
554 Query or set the internal variable that controls whether Octave tries
555 to save all current variables to the file @file{octave-workspace} if it
556 receives a hangup signal.
557 
558 When called from inside a function with the @qcode{"local"} option, the
559 variable is changed locally for the function and any subroutines it calls.
560 The original variable value is restored when exiting the function.
561 @end deftypefn */)
562 {
564  args, nargout,
565  "sighup_dumps_octave_core");
566 }
567 
568 /*
569 %!test
570 %! orig_val = sighup_dumps_octave_core ();
571 %! old_val = sighup_dumps_octave_core (! orig_val);
572 %! assert (orig_val, old_val);
573 %! assert (sighup_dumps_octave_core (), ! orig_val);
574 %! sighup_dumps_octave_core (orig_val);
575 %! assert (sighup_dumps_octave_core (), orig_val);
576 
577 %!error sighup_dumps_octave_core (1, 2)
578 */
579 
580 DEFUN (sigquit_dumps_octave_core, args, nargout,
581  doc: /* -*- texinfo -*-
582 @deftypefn {} {@var{val} =} sigquit_dumps_octave_core ()
583 @deftypefnx {} {@var{old_val} =} sigquit_dumps_octave_core (@var{new_val})
584 @deftypefnx {} {@var{old_val} =} sigquit_dumps_octave_core (@var{new_val}, "local")
585 Query or set the internal variable that controls whether Octave tries
586 to save all current variables to the file @file{octave-workspace} if it
587 receives a quit signal.
588 
589 When called from inside a function with the @qcode{"local"} option, the
590 variable is changed locally for the function and any subroutines it calls.
591 The original variable value is restored when exiting the function.
592 @end deftypefn */)
593 {
595  args, nargout,
596  "sigquit_dumps_octave_core");
597 }
598 
599 /*
600 %!test
601 %! orig_val = sigquit_dumps_octave_core ();
602 %! old_val = sigquit_dumps_octave_core (! orig_val);
603 %! assert (orig_val, old_val);
604 %! assert (sigquit_dumps_octave_core (), ! orig_val);
605 %! sigquit_dumps_octave_core (orig_val);
606 %! assert (sigquit_dumps_octave_core (), orig_val);
607 
608 %!error sigquit_dumps_octave_core (1, 2)
609 */
610 
611 DEFUN (sigterm_dumps_octave_core, args, nargout,
612  doc: /* -*- texinfo -*-
613 @deftypefn {} {@var{val} =} sigterm_dumps_octave_core ()
614 @deftypefnx {} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val})
615 @deftypefnx {} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val}, "local")
616 Query or set the internal variable that controls whether Octave tries
617 to save all current variables to the file @file{octave-workspace} if it
618 receives a terminate signal.
619 
620 When called from inside a function with the @qcode{"local"} option, the
621 variable is changed locally for the function and any subroutines it calls.
622 The original variable value is restored when exiting the function.
623 @end deftypefn */)
624 {
626  args, nargout,
627  "sigterm_dumps_octave_core");
628 }
629 
630 /*
631 %!test
632 %! orig_val = sigterm_dumps_octave_core ();
633 %! old_val = sigterm_dumps_octave_core (! orig_val);
634 %! assert (orig_val, old_val);
635 %! assert (sigterm_dumps_octave_core (), ! orig_val);
636 %! sigterm_dumps_octave_core (orig_val);
637 %! assert (sigterm_dumps_octave_core (), orig_val);
638 
639 %!error sigterm_dumps_octave_core (1, 2)
640 */
641 
OCTAVE_END_NAMESPACE(octave)
bool wait(void)
Definition: child-list.cc:73
void reap(void)
Definition: child-list.cc:45
OCTINTERP_API void dump_octave_core(void)
Definition: load-save.cc:735
void octave_create_interrupt_watcher_thread(octave_sig_handler *handler)
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
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
child_list & __get_child_list__(void)
load_save_system & __get_load_save_system__(void)
bool octave_initialized
Definition: interpreter.cc:94
double signum(double x)
Definition: lo-mappers.h:229
T octave_idx_type m
Definition: mx-inlines.cc:773
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:40
sig_atomic_t octave_interrupt_state
Definition: quit.cc:38
static void deadly_sig_handler(int sig)
Definition: sighandlers.cc:306
static octave_scalar_map make_sig_struct(void)
Definition: sighandlers.cc:448
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:348
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:365
int pipe_handler_error_count
Definition: sighandlers.cc:65
static void set_sig_struct_field(octave_scalar_map &m, const char *signame)
Definition: sighandlers.cc:437
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:259
static bool Vsighup_dumps_octave_core
Definition: sighandlers.cc:76
static void fpe_sig_handler(int)
Definition: sighandlers.cc:318
static bool Vsigterm_dumps_octave_core
Definition: sighandlers.cc:82
interrupt_handler ignore_interrupts(void)
Definition: sighandlers.cc:337
static void generic_sig_handler(int sig)
Definition: sighandlers.cc:273
void respond_to_pending_signals(void)
Definition: sighandlers.cc:110
interrupt_handler catch_interrupts(void)
Definition: sighandlers.cc:326
void sig_handler(int)
Definition: sighandlers.h:46
octave_sig_handler * octave_set_default_signal_handler(int sig)
int octave_num_signals(void)
void * octave_block_child(void)
char * octave_strsignal_wrapper(int signum)
void octave_unblock_child(void *context_arg)
bool octave_get_sig_number(const char *signame, int *signum)
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)
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:584