GNU Octave  6.2.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-2021 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 
61 namespace octave
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)
96 
97  sysdep_cleanup ();
98 
99  throw exit_exception (1);
100  }
101 
102  // Called from octave_quit () to actually do something about the signals
103  // we have caught.
104 
105  void
107  {
108  // The list of signals is relatively short, so we will just go
109  // linearly through the list.
110 
111  // Interrupt signals are currently handled separately.
112 
113  static int sigint;
114  static const bool have_sigint
115  = octave_get_sig_number ("SIGINT", &sigint);
116 
117  static int sigbreak;
118  static const bool have_sigbreak
119  = octave_get_sig_number ("SIGBREAK", &sigbreak);
120 
121  // Termination signals.
122 
123  static int sighup;
124  static const bool have_sighup
125  = octave_get_sig_number ("SIGHUP", &sighup);
126 
127  static int sigquit;
128  static const bool have_sigquit
129  = octave_get_sig_number ("SIGQUIT", &sigquit);
130 
131  static int sigterm;
132  static const bool have_sigterm
133  = octave_get_sig_number ("SIGTERM", &sigterm);
134 
135  // Alarm signals.
136 
137  static int sigalrm;
138  static const bool have_sigalrm
139  = octave_get_sig_number ("SIGALRM", &sigalrm);
140 
141  static int sigvtalrm;
142  static const bool have_sigvtalrm
143  = octave_get_sig_number ("SIGVTALRM", &sigvtalrm);
144 
145  // I/O signals.
146 
147  static int sigio;
148  static const bool have_sigio
149  = octave_get_sig_number ("SIGIO", &sigio);
150 
151  static int siglost;
152  static const bool have_siglost
153  = octave_get_sig_number ("SIGLOST", &siglost);
154 
155  static int sigpipe;
156  static const bool have_sigpipe
157  = octave_get_sig_number ("SIGPIPE", &sigpipe);
158 
159  // Job control signals.
160 
161  static int sigchld;
162  static const bool have_sigchld
163  = octave_get_sig_number ("SIGCHLD", &sigchld);
164 
165  static int sigcld;
166  static const bool have_sigcld
167  = octave_get_sig_number ("SIGCLD", &sigcld);
168 
169  // Resource limit signals.
170 
171  static int sigxcpu;
172  static const bool have_sigxcpu
173  = octave_get_sig_number ("SIGXCPU", &sigxcpu);
174 
175  static int sigxfsz;
176  static const bool have_sigxfsz
177  = octave_get_sig_number ("SIGXFSZ", &sigxfsz);
178 
179  // User signals.
180 
181  static int sigusr1;
182  static const bool have_sigusr1
183  = octave_get_sig_number ("SIGUSR1", &sigusr1);
184 
185  static int sigusr2;
186  static const bool have_sigusr2
187  = octave_get_sig_number ("SIGUSR2", &sigusr2);
188 
189  child_list& kids = __get_child_list__ ("respond_to_pending_signals");
190 
191  for (int sig = 0; sig < octave_num_signals (); sig++)
192  {
193  if (signals_caught[sig])
194  {
195  signals_caught[sig] = false;
196 
197  if ((have_sigchld && sig == sigchld)
198  || (have_sigcld && sig == sigcld))
199  {
200  // FIXME: should we block or ignore?
201  volatile interrupt_handler saved_interrupt_handler
202  = ignore_interrupts ();
203 
204  void *context = octave_block_child ();
205 
206  kids.wait ();
207 
208  set_interrupt_handler (saved_interrupt_handler);
209 
211 
212  kids.reap ();
213  }
214  else if (have_sigpipe && sig == sigpipe)
215  {
216  std::cerr << "warning: broken pipe" << std::endl;
217 
218  // Don't loop forever on account of this.
219  // FIXME: is this really needed? Does it do anything
220  // useful now?
221 
222  if (pipe_handler_error_count++ > 100
223  && octave_interrupt_state >= 0)
225  }
226  else if (have_sighup && sig == sighup)
228  else if (have_sigquit && sig == sigquit)
230  else if (have_sigterm && sig == sigterm)
232  else if ((have_sigalrm && sig == sigalrm)
233  || (have_sigvtalrm && sig == sigvtalrm)
234  || (have_sigio && sig == sigio)
235  || (have_siglost && sig == siglost)
236  || (have_sigxcpu && sig == sigxcpu)
237  || (have_sigxfsz && sig == sigxfsz)
238  || (have_sigusr1 && sig == sigusr1)
239  || (have_sigusr2 && sig == sigusr2))
240  std::cerr << "warning: ignoring signal: "
241  << octave_strsignal_wrapper (sig)
242  << std::endl;
243  else if ((have_sigint && sig == sigint)
244  || (have_sigbreak && sig == sigbreak))
245  ; // Handled separately; do nothing.
246  else
247  std::cerr << "warning: ignoring unexpected signal: "
248  << octave_strsignal_wrapper (sig)
249  << std::endl;
250  }
251  }
252  }
253 
254  sig_handler *
255  set_signal_handler (int sig, sig_handler *handler, bool restart_syscalls)
256  {
257  return octave_set_signal_handler_internal (sig, handler, restart_syscalls);
258  }
259 
260  sig_handler *
261  set_signal_handler (const char *signame, sig_handler *handler,
262  bool restart_syscalls)
263  {
264  return octave_set_signal_handler_by_name (signame, handler,
265  restart_syscalls);
266  }
267 
268  static void
270  {
271  // FIXME: this function may execute in a separate signal handler or
272  // signal watcher thread so it should probably be more careful about
273  // how it accesses global objects.
274 
276 
277  signals_caught[sig] = true;
278 
279  static int sigint;
280  static const bool have_sigint
281  = octave_get_sig_number ("SIGINT", &sigint);
282 
283  static int sigbreak;
284  static const bool have_sigbreak
285  = octave_get_sig_number ("SIGBREAK", &sigbreak);
286 
287  if ((have_sigint && sig == sigint)
288  || (have_sigbreak && sig == sigbreak))
289  {
290  if (! octave_initialized)
291  exit (1);
292 
293  if (can_interrupt)
294  {
297  }
298  }
299  }
300 
301  static void
303  {
304  std::cerr << "fatal: caught signal "
305  << octave_strsignal_wrapper (sig)
306  << " -- stopping myself..." << std::endl;
307 
309 
310  octave_raise_wrapper (sig);
311  }
312 
313  static void
315  {
316  // FIXME: is there something better we can do?
317 
318  std::cerr << "warning: floating point exception" << std::endl;
319  }
320 
321  interrupt_handler
323  {
325 
326  retval.int_handler = set_signal_handler ("SIGINT", generic_sig_handler);
327  retval.brk_handler = set_signal_handler ("SIGBREAK", generic_sig_handler);
328 
329  return retval;
330  }
331 
332  interrupt_handler
334  {
336 
337  retval.int_handler = set_signal_handler ("SIGINT", SIG_IGN);
338  retval.brk_handler = set_signal_handler ("SIGBREAK", SIG_IGN);
339 
340  return retval;
341  }
342 
343  interrupt_handler
345  bool restart_syscalls)
346  {
348 
349  retval.int_handler = set_signal_handler ("SIGINT", h.int_handler,
350  restart_syscalls);
351 
352  retval.brk_handler = set_signal_handler ("SIGBREAK", h.brk_handler,
353  restart_syscalls);
354 
355  return retval;
356  }
357 
358  // Install all the handlers for the signals we might care about.
359 
360  void
362  {
363  if (! signals_caught)
364  signals_caught = new bool [octave_num_signals ()];
365 
366  for (int i = 0; i < octave_num_signals (); i++)
367  signals_caught[i] = false;
368 
369  // Interrupt signals.
370 
371  catch_interrupts ();
372 
373  // Program Error signals. These are most likely unrecoverable for
374  // us.
375 
380  // SIGIOT is normally another name for SIGABRT.
385 
386  // Handle SIGFPE separately.
387 
389 
390  // Handle other signals for which the default action is to terminate
391  // the program.
392 
393  // Termination signals.
394 
398 
399  // Alarm signals.
400 
403 
404  // I/O signals.
405 
408 
409  // Job control signals. We only recognize signals about child
410  // processes.
411 
414 
415  // Resource limit signals.
416 
417  // FIXME: does it really make sense to try to handle the CPU limit
418  // signal?
419 
422 
423  // User signals.
424 
427 
428  // This does nothing on Windows systems.
430  }
431 
432  static void
433  set_sig_struct_field (octave_scalar_map& m, const char *signame)
434  {
435  int signum;
436 
437  // The names in the struct do not include the leading "SIG" prefix.
438 
439  if (octave_get_sig_number (signame, &signum))
440  m.assign (&signame[3], signum);
441  }
442 
443  static octave_scalar_map
445  {
447 
448  set_sig_struct_field (m, "SIGABRT");
449  set_sig_struct_field (m, "SIGALRM");
450  set_sig_struct_field (m, "SIGBUS");
451  set_sig_struct_field (m, "SIGCHLD");
452  set_sig_struct_field (m, "SIGCLD");
453  set_sig_struct_field (m, "SIGCONT");
454  set_sig_struct_field (m, "SIGEMT");
455  set_sig_struct_field (m, "SIGFPE");
456  set_sig_struct_field (m, "SIGHUP");
457  set_sig_struct_field (m, "SIGILL");
458  set_sig_struct_field (m, "SIGINFO");
459  set_sig_struct_field (m, "SIGINT");
460  set_sig_struct_field (m, "SIGIO");
461  set_sig_struct_field (m, "SIGIOT");
462  set_sig_struct_field (m, "SIGKILL");
463  set_sig_struct_field (m, "SIGLOST");
464  set_sig_struct_field (m, "SIGPIPE");
465  set_sig_struct_field (m, "SIGPOLL");
466  set_sig_struct_field (m, "SIGPROF");
467  set_sig_struct_field (m, "SIGPWR");
468  set_sig_struct_field (m, "SIGQUIT");
469  set_sig_struct_field (m, "SIGSEGV");
470  set_sig_struct_field (m, "SIGSTKFLT");
471  set_sig_struct_field (m, "SIGSTOP");
472  set_sig_struct_field (m, "SIGSYS");
473  set_sig_struct_field (m, "SIGTERM");
474  set_sig_struct_field (m, "SIGTRAP");
475  set_sig_struct_field (m, "SIGTSTP");
476  set_sig_struct_field (m, "SIGTTIN");
477  set_sig_struct_field (m, "SIGTTOU");
478  set_sig_struct_field (m, "SIGUNUSED");
479  set_sig_struct_field (m, "SIGURG");
480  set_sig_struct_field (m, "SIGUSR1");
481  set_sig_struct_field (m, "SIGUSR2");
482  set_sig_struct_field (m, "SIGVTALRM");
483  set_sig_struct_field (m, "SIGWINCH");
484  set_sig_struct_field (m, "SIGXCPU");
485  set_sig_struct_field (m, "SIGXFSZ");
486 
487  return m;
488  }
489 }
490 
491 DEFUN (SIG, args, ,
492  doc: /* -*- texinfo -*-
493 @deftypefn {} {} SIG ()
494 Return a structure containing Unix signal names and their defined values.
495 @end deftypefn */)
496 {
497  if (args.length () != 0)
498  print_usage ();
499 
501 
502  return ovl (m);
503 }
504 
505 /*
506 %!assert (isstruct (SIG ()))
507 %!assert (! isempty (SIG ()))
508 
509 %!error SIG (1)
510 */
511 
512 DEFUN (debug_on_interrupt, args, nargout,
513  doc: /* -*- texinfo -*-
514 @deftypefn {} {@var{val} =} debug_on_interrupt ()
515 @deftypefnx {} {@var{old_val} =} debug_on_interrupt (@var{new_val})
516 @deftypefnx {} {} debug_on_interrupt (@var{new_val}, "local")
517 Query or set the internal variable that controls whether Octave will try
518 to enter debugging mode when it receives an interrupt signal (typically
519 generated with @kbd{C-c}).
520 
521 If a second interrupt signal is received before reaching the debugging mode,
522 a normal interrupt will occur.
523 
524 When called from inside a function with the @qcode{"local"} option, the
525 variable is changed locally for the function and any subroutines it calls.
526 The original variable value is restored when exiting the function.
527 @seealso{debug_on_error, debug_on_warning}
528 @end deftypefn */)
529 {
530  return set_internal_variable (octave::Vdebug_on_interrupt, args, nargout,
531  "debug_on_interrupt");
532 }
533 
534 /*
535 %!test
536 %! orig_val = debug_on_interrupt ();
537 %! old_val = debug_on_interrupt (! orig_val);
538 %! assert (orig_val, old_val);
539 %! assert (debug_on_interrupt (), ! orig_val);
540 %! debug_on_interrupt (orig_val);
541 %! assert (debug_on_interrupt (), orig_val);
542 
543 %!error (debug_on_interrupt (1, 2))
544 */
545 
546 DEFUN (sighup_dumps_octave_core, args, nargout,
547  doc: /* -*- texinfo -*-
548 @deftypefn {} {@var{val} =} sighup_dumps_octave_core ()
549 @deftypefnx {} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val})
550 @deftypefnx {} {} sighup_dumps_octave_core (@var{new_val}, "local")
551 Query or set the internal variable that controls whether Octave tries
552 to save all current variables to the file @file{octave-workspace} if it
553 receives a hangup signal.
554 
555 When called from inside a function with the @qcode{"local"} option, the
556 variable is changed locally for the function and any subroutines it calls.
557 The original variable value is restored when exiting the function.
558 @end deftypefn */)
559 {
561  args, nargout,
562  "sighup_dumps_octave_core");
563 }
564 
565 /*
566 %!test
567 %! orig_val = sighup_dumps_octave_core ();
568 %! old_val = sighup_dumps_octave_core (! orig_val);
569 %! assert (orig_val, old_val);
570 %! assert (sighup_dumps_octave_core (), ! orig_val);
571 %! sighup_dumps_octave_core (orig_val);
572 %! assert (sighup_dumps_octave_core (), orig_val);
573 
574 %!error (sighup_dumps_octave_core (1, 2))
575 */
576 
577 DEFUN (sigquit_dumps_octave_core, args, nargout,
578  doc: /* -*- texinfo -*-
579 @deftypefn {} {@var{val} =} sigquit_dumps_octave_core ()
580 @deftypefnx {} {@var{old_val} =} sigquit_dumps_octave_core (@var{new_val})
581 @deftypefnx {} {} sigquit_dumps_octave_core (@var{new_val}, "local")
582 Query or set the internal variable that controls whether Octave tries
583 to save all current variables to the file @file{octave-workspace} if it
584 receives a quit signal.
585 
586 When called from inside a function with the @qcode{"local"} option, the
587 variable is changed locally for the function and any subroutines it calls.
588 The original variable value is restored when exiting the function.
589 @end deftypefn */)
590 {
592  args, nargout,
593  "sigquit_dumps_octave_core");
594 }
595 
596 /*
597 %!test
598 %! orig_val = sigquit_dumps_octave_core ();
599 %! old_val = sigquit_dumps_octave_core (! orig_val);
600 %! assert (orig_val, old_val);
601 %! assert (sigquit_dumps_octave_core (), ! orig_val);
602 %! sigquit_dumps_octave_core (orig_val);
603 %! assert (sigquit_dumps_octave_core (), orig_val);
604 
605 %!error (sigquit_dumps_octave_core (1, 2))
606 */
607 
608 DEFUN (sigterm_dumps_octave_core, args, nargout,
609  doc: /* -*- texinfo -*-
610 @deftypefn {} {@var{val} =} sigterm_dumps_octave_core ()
611 @deftypefnx {} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val})
612 @deftypefnx {} {} sigterm_dumps_octave_core (@var{new_val}, "local")
613 Query or set the internal variable that controls whether Octave tries
614 to save all current variables to the file @file{octave-workspace} if it
615 receives a terminate signal.
616 
617 When called from inside a function with the @qcode{"local"} option, the
618 variable is changed locally for the function and any subroutines it calls.
619 The original variable value is restored when exiting the function.
620 @end deftypefn */)
621 {
623  args, nargout,
624  "sigterm_dumps_octave_core");
625 }
626 
627 /*
628 %!test
629 %! orig_val = sigterm_dumps_octave_core ();
630 %! old_val = sigterm_dumps_octave_core (! orig_val);
631 %! assert (orig_val, old_val);
632 %! assert (sigterm_dumps_octave_core (), ! orig_val);
633 %! sigterm_dumps_octave_core (orig_val);
634 %! assert (sigterm_dumps_octave_core (), orig_val);
635 
636 %!error (sigterm_dumps_octave_core (1, 2))
637 */
void reap(void)
Definition: child-list.cc:58
bool wait(void)
Definition: child-list.cc:86
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
bool octave_initialized
Definition: interpreter.cc:92
void dump_octave_core(void)
Definition: load-save.cc:1540
T octave_idx_type m
Definition: mx-inlines.cc:773
double signum(double x)
Definition: lo-mappers.h:222
static bool Vsigquit_dumps_octave_core
Definition: sighandlers.cc:79
static bool Vsigterm_dumps_octave_core
Definition: sighandlers.cc:82
sig_handler * set_signal_handler(int sig, sig_handler *handler, bool restart_syscalls)
Definition: sighandlers.cc:255
interrupt_handler set_interrupt_handler(const volatile interrupt_handler &h, bool restart_syscalls)
Definition: sighandlers.cc:344
static bool Vsighup_dumps_octave_core
Definition: sighandlers.cc:76
void respond_to_pending_signals(void)
Definition: sighandlers.cc:106
static void generic_sig_handler(int sig)
Definition: sighandlers.cc:269
int pipe_handler_error_count
Definition: sighandlers.cc:65
void sig_handler(int)
Definition: sighandlers.h:46
static llvm::LLVMContext & context
Definition: jit-typeinfo.cc:80
interrupt_handler ignore_interrupts(void)
Definition: sighandlers.cc:333
static bool * signals_caught
Definition: sighandlers.cc:85
bool Vdebug_on_interrupt
Definition: sighandlers.cc:71
static octave_scalar_map make_sig_struct(void)
Definition: sighandlers.cc:444
void sysdep_cleanup(void)
Definition: sysdep.cc:451
static void fpe_sig_handler(int)
Definition: sighandlers.cc:314
static void deadly_sig_handler(int sig)
Definition: sighandlers.cc:302
static void set_sig_struct_field(octave_scalar_map &m, const char *signame)
Definition: sighandlers.cc:433
bool can_interrupt
Definition: sighandlers.cc:68
interrupt_handler catch_interrupts(void)
Definition: sighandlers.cc:322
child_list & __get_child_list__(const std::string &who)
void install_signal_handlers(void)
Definition: sighandlers.cc:361
static void my_friendly_exit(int sig, bool save_vars=true)
Definition: sighandlers.cc:88
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
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
void octave_create_interrupt_watcher_thread(octave_sig_handler *handler)
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
octave_value set_internal_variable(bool &var, const octave_value_list &args, int nargout, const char *nm)
Definition: variables.cc:608