diff liboctave/util/cmd-edit.cc @ 24520:c5c11b07598a

refactor signal handling (bug #52757) Given that any library code may now be multi-threaded it is not likely to be save to jump out of a signal handler when executing a call to a library function. We are almost assured to fail if the call to siglongjmp occurs in a different thread from the corresponding call to sigsetjmp. Similarly, we should avoid calling the interrupt signal handler function in an arbitrary thread. This is already done by default on Windows systems. On Posix systems, we now set up a separate thread to handle asynchronous signals (not just SIGINT). We no longer attempt to jump out of the signal handler. Instead, we only set global status variables and respond to them in octave_quit. This means that some external library functions are no longer interruptible. If that becomes important, then we will need to look for other alternatives such as setting up worker threads that can be canceled when a SIGINT is detected. * sighandlers.cc (interrupt_manager, base_interrupt_manager, w32_interrupt_manager, posix_interrupt_manager): Delete classes and all uses. (respond_to_pending_signals): Rename from signal_handler. Change all uses. Take action on more signals. (generic_sig_handler): Simply record that a signal was caught and add it to the list of caught signals. (deadly_sig_handler): New function. (fpe_sig_handler): Rename from sigfpe_handler. Don't make specific to Alpha systems. Simply warn that an exception has occurred. (sigint_handler): Simply record that an interrupt signal was caught. (sigterm_handler, sigpipe_handler): Delete. (install_signal_handlers): Rework actions for various signals. (Vsigquit_dumps_octave_core): New static variable. (Fsigquit_dumps_octave_core): New function. * io.txi: Document sigquit_dumps_octave_core. * f77-fcn.h, f77-fcn.c (xSTRINGIZE, STRINGIZE, F77_XFCN_ERROR): Delete macros. (F77_XFCN): Don't do setjmp/longjmp exception handling. (f77_exception_encountered): Delete global variable. (XSTOPX): Don't set f77_exception_encountered. If message is empty, report "unknown error in fortran subroutine". * eigs-base.cc, gsvd.cc: Delete all direct uses of f77_exception_encountered. * liboctave/util/f77-extern.cc: Delete file. * liboctave/util/module.mk: Update. * cmd-edit.h, cmd-edit.cc (command_editor::interrupt_exception): New class. (command_editor::handle_interrupt_signal): New static function. (command_editor::do_handle_interrupt_signal): New virtual function. (command_editor::event_hanlder): Call handle_interrupt_signal if octave_interrupt_state is not zero. (command_editor::instance_ok): Set event hook here. (command_editor::add_event_hook): Not here. (command_editor::remove_event_hook): Never remove event hook. (gnu_readline::do_handle_interrupt_signal): New function. (gnu_readline::do_readline): Retry if an interrupt exception occurs inside readline. * oct-rl-edit.h, oct-rl-edit.c (octave_rl_recover_from_interrupt): New function. * quit.h, cquit.c (current_context, octave_save_current_context, octave_restore_current_context, octave_jump_to_enclosing_context, octave_interrupt_immediately, octave_jmp_buf): Delete. * quit.h: Don't include <setjmp.h> (octave_set_current_context): Delete macro. (octave_exit_exception_status, octave_exit_exception_safe_to_return): Mark as deprecated. (BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_1): Delete. (BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_2): Delete. (BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE, END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE): Define to only create a dummy do-while scope. (BEGIN_INTERRUPT_WITH_EXCEPTIONS, END_INTERRUPT_WITH_EXCEPTIONS): Define to only create a dummy scope. * interpreter.cc (interpreter::recover_from_exception): Don't reset octave_interrupt_immediately. * main-cli.cc (main): Call octave_block_async_signals. * main.in.cc (main): Call octave_block_async_signals initially. Only in install signal handlers and unblock signals if starting managed subprocess. * main-window.cc (octave_interpreter::executed): Don't unblock interrupt signals. * signal-wrappers.h, signal-wrappers.c (signal_watcher, octave_async_signals, block_or_unblock_signal_by_name): New static functions. (octave_set_default_signal_handler, octave_set_default_signal_handler_by_name, octave_block_signal_by_name, octave_unblock_signal_by_name, octave_create_interrupt_watcher_thread, octave_block_async_signals, octave_unblock_async_signals): New functions. (octave_block_interrupt_signal, octave_unblock_interrupt_signal): Treat SIGBREAK as an interrupt signal. (octave_block_child): Also handle SIGCLD the same as SIGCHLD. (print_sigset, print_sigmask): New static functions. (octave_show_sigmask): New function.
author John W. Eaton <jwe@octave.org>
date Wed, 03 Jan 2018 07:52:11 -0500
parents 061a343089be
children 194eb4bd202b
line wrap: on
line diff
--- a/liboctave/util/cmd-edit.cc	Thu Jan 04 10:09:23 2018 -0500
+++ b/liboctave/util/cmd-edit.cc	Wed Jan 03 07:52:11 2018 -0500
@@ -195,6 +195,8 @@
 
     void do_interrupt (bool);
 
+    void do_handle_interrupt_signal (void);
+
     static int operate_and_get_next (int, int);
 
     static int history_search_backward (int, int);
@@ -287,20 +289,31 @@
 
     const char *p = prompt.c_str ();
 
-    BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
-
-    char *line = ::octave_rl_readline (p);
-
-    if (line)
+    while (true)
       {
-        retval = line;
+        try
+          {
+            char *line = ::octave_rl_readline (p);
+
+            if (line)
+              {
+                retval = line;
 
-        free (line);
+                free (line);
+              }
+            else
+              eof = true;
+
+            break;
+          }
+        catch (command_editor::interrupt_exception&)
+          {
+            // Is this right?
+            std::cout << "\n";
+
+            // Try again...
+          }
       }
-    else
-      eof = true;
-
-    END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
 
     return retval;
   }
@@ -782,6 +795,17 @@
     ::octave_rl_done (arg);
   }
 
+  void
+  gnu_readline::do_handle_interrupt_signal (void)
+  {
+    octave_signal_caught = 0;
+    octave_interrupt_state = 0;
+
+    ::octave_rl_recover_from_interrupt ();
+
+    throw command_editor::interrupt_exception ();
+  }
+
   int
   gnu_readline::operate_and_get_next (int /* count */, int /* c */)
   {
@@ -1064,7 +1088,11 @@
         make_command_editor ();
 
         if (instance)
-          singleton_cleanup_list::add (cleanup_instance);
+          {
+            instance->set_event_hook (event_handler);
+
+            singleton_cleanup_list::add (cleanup_instance);
+          }
       }
 
     if (! instance)
@@ -1131,6 +1159,9 @@
   int
   command_editor::event_handler (void)
   {
+    if (octave_interrupt_state)
+      handle_interrupt_signal ();
+
     event_hook_lock.lock ();
 
     std::set<event_hook_fcn> hook_set (event_hook_set);
@@ -1539,12 +1570,7 @@
   {
     autolock guard (event_hook_lock);
 
-    if (instance_ok ())
-      {
-        event_hook_set.insert (f);
-
-        instance->set_event_hook (event_handler);
-      }
+    event_hook_set.insert (f);
   }
 
   void
@@ -1552,16 +1578,11 @@
   {
     autolock guard (event_hook_lock);
 
-    if (instance_ok ())
-      {
-        auto p = event_hook_set.find (f);
+    auto p = event_hook_set.find (f);
 
-        if (p != event_hook_set.end ())
-          event_hook_set.erase (p);
+    if (p != event_hook_set.end ())
+      event_hook_set.erase (p);
 
-        if (event_hook_set.empty ())
-          instance->restore_event_hook ();
-      }
   }
 
   void
@@ -1629,6 +1650,13 @@
     return retval;
   }
 
+  void
+  command_editor::handle_interrupt_signal (void)
+  {
+    if (instance_ok ())
+      instance->do_handle_interrupt_signal ();
+  }
+
   // Return a string which will be printed as a prompt.  The string may
   // contain special characters which are decoded as follows:
   //