changeset 29306:0231189f630d

provide interpreter methods for pausing, resuming, and stopping evaluation * interpreter.h, interpreter.cc (interpreter::pause, interpreter::resume, interpreter::stop): New methods. * pt-eval.h, pt-eval.cc (tree_evaluator::m_break_on_next_stmt): New member variable. (tree_evaluator::do_breakpoint): Also check m_break_on_next_stmt. (tree_evaluator::break_on_next_statement): New functions. (tree_evaluator::reset_debug_state): Also set m_debug_mode if m_break_on_next_stmt is true.
author John W. Eaton <jwe@octave.org>
date Wed, 20 Jan 2021 16:53:16 -0500
parents 477f7d6c61e4
children b2d62cfac9e6
files libinterp/corefcn/interpreter.cc libinterp/corefcn/interpreter.h libinterp/parse-tree/pt-eval.cc libinterp/parse-tree/pt-eval.h
diffstat 4 files changed, 90 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/interpreter.cc	Wed Jan 20 16:45:45 2021 -0500
+++ b/libinterp/corefcn/interpreter.cc	Wed Jan 20 16:53:16 2021 -0500
@@ -1719,22 +1719,55 @@
         first = false;
       }
 
-    // Send SIGINT to all other processes in our process group.  The
-    // signal handler for SIGINT will set a global variable indicating
-    // an interrupt has happened.  That variable is checked in many
-    // places in the Octave interpreter and eventually results in an
-    // interrupt_exception being thrown.  Finally, that exception is
-    // caught and returns control to one of the read-eval-print loops or
-    // to the server loop.  We use a signal instead of just setting the
-    // global variables here so that we will probably send interrupt
-    // signals to any subprocesses as well as interrupt execution of the
-    // interpreter.
+    // Send SIGINT to Octave and (optionally) all other processes in its
+    // process group.  The signal handler for SIGINT will set a global
+    // variable indicating an interrupt has happened.  That variable is
+    // checked in many places in the Octave interpreter and eventually
+    // results in an interrupt_exception being thrown.  Finally, that
+    // exception is caught and returns control to one of the
+    // read-eval-print loops or to the server loop.  We use a signal
+    // instead of just setting the global variables here so that we will
+    // probably send interrupt signals to any subprocesses as well as
+    // interrupt execution of the interpreter.
 
-    pid_t pid = m_interrupt_all_in_process_group ? 0 : octave_getpid_wrapper ();
+    pid_t pid
+      = m_interrupt_all_in_process_group ? 0 : octave_getpid_wrapper ();
 
     octave_kill_wrapper (pid, sigint);
   }
 
+  void interpreter::pause (void)
+  {
+    // FIXME: To be reliable, these tree_evaluator functions must be
+    // made thread safe.
+
+    m_evaluator.break_on_next_statement (true);
+    m_evaluator.reset_debug_state ();
+  }
+
+  void interpreter::stop (void)
+  {
+    // FIXME: To be reliable, these tree_evaluator functions must be
+    // made thread safe.
+
+    if (m_evaluator.in_debug_repl ())
+      m_evaluator.dbquit (true);
+    else
+      interrupt ();
+  }
+
+  void interpreter::resume (void)
+  {
+    // FIXME: To be reliable, these tree_evaluator functions must be
+    // made thread safe.
+
+    // FIXME: Should there be any feeback about not doing anything if
+    // not in debug mode?
+
+    if (m_evaluator.in_debug_repl ())
+      m_evaluator.dbcont ();
+  }
+
   void interpreter::handle_exception (const execution_exception& ee)
   {
     m_error_system.save_exception (ee);
--- a/libinterp/corefcn/interpreter.h	Wed Jan 20 16:45:45 2021 -0500
+++ b/libinterp/corefcn/interpreter.h	Wed Jan 20 16:53:16 2021 -0500
@@ -479,6 +479,17 @@
 
     void interrupt (void);
 
+    // Pause interpreter execution at the next available statement and
+    // enter the debugger.
+    void pause (void);
+
+    // Exit debugger or stop execution and return to the top-level REPL
+    // or server loop.
+    void stop (void);
+
+    // Resume interpreter execution if paused.
+    void resume (void);
+
     void handle_exception (const execution_exception& ee);
 
     void recover_from_exception (void);
--- a/libinterp/parse-tree/pt-eval.cc	Wed Jan 20 16:45:45 2021 -0500
+++ b/libinterp/parse-tree/pt-eval.cc	Wed Jan 20 16:53:16 2021 -0500
@@ -117,10 +117,7 @@
 
     bool in_debug_repl (void) const { return m_in_debug_repl; }
 
-    void dbcont (void)
-    {
-      m_execution_mode = EX_CONTINUE;
-    }
+    void dbcont (void) { m_execution_mode = EX_CONTINUE; }
 
     void dbquit (bool all = false)
     {
@@ -1191,7 +1188,9 @@
   void
   tree_evaluator::reset_debug_state (void)
   {
-    m_debug_mode = (m_bp_table.have_breakpoints () || m_dbstep_flag != 0
+    m_debug_mode = (m_bp_table.have_breakpoints ()
+                    || m_dbstep_flag != 0
+                    || m_break_on_next_stmt
                     || in_debug_repl ());
   }
 
@@ -4151,6 +4150,11 @@
           m_dbstep_flag = -1;
       }
 
+    if (! break_on_this_statement)
+      break_on_this_statement = m_break_on_next_stmt;
+
+    m_break_on_next_stmt = false;
+
     if (break_on_this_statement)
       {
         m_dbstep_flag = 0;
--- a/libinterp/parse-tree/pt-eval.h	Wed Jan 20 16:45:45 2021 -0500
+++ b/libinterp/parse-tree/pt-eval.h	Wed Jan 20 16:53:16 2021 -0500
@@ -134,8 +134,8 @@
         m_debug_mode (false), m_quiet_breakpoint_flag (false),
         m_debugger_stack (), m_exit_status (0), m_max_recursion_depth (256),
         m_whos_line_format ("  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;\n"),
-        m_silent_functions (false), m_string_fill_char (' '),
-        m_PS4 ("+ "), m_dbstep_flag (0), m_echo (ECHO_OFF),
+        m_silent_functions (false), m_string_fill_char (' '), m_PS4 ("+ "),
+        m_dbstep_flag (0), m_break_on_next_stmt (false), m_echo (ECHO_OFF),
         m_echo_state (false), m_echo_file_name (), m_echo_file_pos (1),
         m_echo_files (), m_in_top_level_repl (false),
         m_server_mode (false), m_in_loop_command (false),
@@ -642,6 +642,9 @@
 
     void dbcont (void);
 
+    // Return true if we are in the debug repl and m_execution_mode is
+    // set to exit the debugger.  Otherwise, do nothing.
+
     void dbquit (bool all = false);
 
     octave_value PS4 (const octave_value_list& args, int nargout);
@@ -748,6 +751,23 @@
 
     void set_dbstep_flag (int step) { m_dbstep_flag = step; }
 
+    bool break_on_next_statement (void) const
+    {
+      return m_break_on_next_stmt;
+    }
+
+    bool break_on_next_statement (bool val)
+    {
+      bool old_val = m_break_on_next_stmt;
+      m_break_on_next_stmt = val;
+      return old_val;
+    }
+
+    void set_break_on_next_statement (bool val)
+    {
+      m_break_on_next_stmt = val;
+    }
+
     octave_value echo (const octave_value_list& args, int nargout);
 
     int echo (void) const { return m_echo; }
@@ -871,6 +891,10 @@
     // If < 0, stop executing at the next possible stopping point.
     int m_dbstep_flag;
 
+    // If TRUE, and we are not stopping for another reason (dbstep or a
+    // breakpoint) then stop at next statement and enter the debugger.
+    bool m_break_on_next_stmt;
+
     // Echo commands as they are executed?
     //
     //   1  ==>  echo commands read from script files