diff libinterp/corefcn/interpreter.cc @ 23117:17a3567a7b01

separate final interpreter initialization from execution * libgui_src/octave-interpreter.cc (octave_interpreter::execute): Perform final initialization separately from execution. * interpreter.h, interpreter.cc (interpreter::m_initialized): New data member. (interpreter::initialized): New function. (interpreter::~interpreter): Always call cleanup. (interpreter::initialize): Rename from execute_internal. Don't call main_loop here. Protect from being called more than once. Set m_initialized when done. (interpreter::execute): Call initialize and main_loop here. (interpreter::cleanup): Don't protect from recursive calls. * octave.h, octave.cc (application::interpreter_initialized, application::initialize_interpreter, application::delete_interpreter): New functions. (cli_application::execute): Also delete interpreter here. * embedded.cc: Update example code.
author John W. Eaton <jwe@octave.org>
date Mon, 30 Jan 2017 15:13:29 -0500
parents 252975fdc444
children 5a91168a30be
line wrap: on
line diff
--- a/libinterp/corefcn/interpreter.cc	Tue Nov 15 23:10:15 2016 +0100
+++ b/libinterp/corefcn/interpreter.cc	Mon Jan 30 15:13:29 2017 -0500
@@ -359,11 +359,16 @@
 {
   tree_evaluator *current_evaluator = 0;
 
+  // Create an interpreter object and perform initialization up to the
+  // point of setting reading command history and setting the load
+  // path.
+
   interpreter::interpreter (application *app_context)
     : m_app_context (app_context), m_evaluator (new tree_evaluator (this)),
       m_interactive (false), m_read_site_files (true),
       m_read_init_files (m_app_context != 0), m_verbose (false),
-      m_inhibit_startup_message (false), m_load_path_initialized (false)
+      m_inhibit_startup_message (false), m_load_path_initialized (false),
+      m_history_initialized (false), m_initialized (false)
   {
     current_evaluator = m_evaluator;
 
@@ -407,7 +412,7 @@
 
     initialize_error_handlers ();
 
-    if (app_context)
+    if (m_app_context)
       octave::install_signal_handlers ();
     else
       quit_allowed = false;
@@ -425,7 +430,7 @@
     bool line_editing = false;
     bool traditional = false;
 
-    if (app_context)
+    if (m_app_context)
       {
         // Embedded interpeters don't execute command line options or
         const cmdline_options& options = m_app_context->options ();
@@ -433,7 +438,7 @@
         // Make all command-line arguments available to startup files,
         // including PKG_ADD files.
 
-        app_context->intern_argv (options.all_args ());
+        m_app_context->intern_argv (options.all_args ());
 
         bool is_octave_program = m_app_context->is_octave_program ();
 
@@ -497,31 +502,35 @@
 
   interpreter::~interpreter (void)
   {
-    if (! m_app_context)
-      cleanup ();
+    cleanup ();
 
     current_evaluator = 0;
 
     delete m_evaluator;
   }
 
-  int interpreter::execute (void)
+  // Read the history file unless a command-line option inhibits that.
+
+  void interpreter::initialize_history (bool read_history_file)
   {
-    int exit_status = 0;
+    if (! m_history_initialized)
+      {
+        // Allow command-line option to override.
 
-    try
-      {
-        exit_status = execute_internal ();
+        if (m_app_context)
+          {
+            const cmdline_options& options = m_app_context->options ();
+
+            read_history_file = options.read_history_file ();
+          }
+
+        ::initialize_history (read_history_file);
+
+        if (! m_app_context)
+          octave::command_history::ignore_entries ();
+
+        m_history_initialized = true;
       }
-    catch (const octave::exit_exception& ex)
-      {
-        exit_status = ex.exit_status ();
-      }
-
-    if (m_app_context)
-      cleanup ();
-
-    return exit_status;
   }
 
   // Set the initial path to the system default unless command-line
@@ -561,57 +570,42 @@
       }
   }
 
-  void interpreter::initialize_history (bool read_history_file)
-  {
-    if (! m_history_initialized)
-      {
-        // Allow command-line option to override.
-
-        if (m_app_context)
-          {
-            const cmdline_options& options = m_app_context->options ();
+  // This may be called separately from execute
 
-            read_history_file = options.read_history_file ();
-          }
-
-        ::initialize_history (read_history_file);
+  int interpreter::initialize (void)
+  {
+    if (m_initialized)
+      return 0;
 
-        if (! m_app_context)
-          octave::command_history::ignore_entries ();
-
-        m_history_initialized = true;
-      }
-  }
-
-  int interpreter::execute_internal (void)
-  {
     display_startup_message ();
 
-    // Initializing the load path may execute PKG_ADD files.  It also
-    // allows the path to be initialized between the calls to create and
-    // executeexecute the interpreter.
+    // Wait to read the history file until the interpreter reads input
+    // files and begins evaluating commands.
+
+    initialize_history ();
+
+    // Initializing the load path may execute PKG_ADD files, so can't be
+    // done until the interpreter is ready to execute commands.
+
+    // Deferring it to the execute step also allows the path to be
+    // initialized between creating and execute the interpreter, for
+    // example, to set a custom path for an embedded interpreter.
 
     initialize_load_path ();
 
-    initialize_history ();
+    // We ignore errors in startup files.
 
-    // Don't fail, but return non-zero if there is an error in a startup
-    // file.
+    execute_startup_files ();
 
     int exit_status = 0;
 
-    int status = execute_startup_files ();
-
-    if (status)
-      exit_status = status;
-
     if (m_app_context)
       {
         const cmdline_options& options = m_app_context->options ();
 
         if (m_app_context->have_eval_option_code ())
           {
-            status = execute_eval_option_code ();
+            int status = execute_eval_option_code ();
 
             if (status )
               exit_status = status;
@@ -626,7 +620,7 @@
 
         if (m_app_context->have_script_file ())
           {
-            status = execute_command_line_file ();
+            int status = execute_command_line_file ();
 
             if (status)
               exit_status = status;
@@ -651,7 +645,26 @@
 
     octave::command_editor::reset_current_command_number (1);
 
-    return main_loop ();
+    m_initialized = true;
+
+    return exit_status;
+  }
+
+  int interpreter::execute (void)
+  {
+    try
+      {
+        int status = initialize ();
+
+        if (! m_initialized)
+          return status;
+
+        return main_loop ();
+      }
+    catch (const octave::exit_exception& ex)
+      {
+        return ex.exit_status ();
+      }
   }
 
   void interpreter::display_startup_message (void) const
@@ -1050,8 +1063,6 @@
 
   void interpreter::cleanup (void)
   {
-    static bool deja_vu = false;
-
     // If we are attached to a GUI, process pending events and
     // disconnect the link.
 
@@ -1073,52 +1084,47 @@
         OCTAVE_SAFE_CALL (octave::flush_stdout, ());
       }
 
-    if (! deja_vu)
-      {
-        deja_vu = true;
+    // Do this explicitly so that destructors for mex file objects
+    // are called, so that functions registered with mexAtExit are
+    // called.
+    OCTAVE_SAFE_CALL (clear_mex_functions, ());
 
-        // Do this explicitly so that destructors for mex file objects
-        // are called, so that functions registered with mexAtExit are
-        // called.
-        OCTAVE_SAFE_CALL (clear_mex_functions, ());
+    OCTAVE_SAFE_CALL (octave::command_editor::restore_terminal_state, ());
 
-        OCTAVE_SAFE_CALL (octave::command_editor::restore_terminal_state, ());
+    OCTAVE_SAFE_CALL (octave_history_write_timestamp, ());
 
-        OCTAVE_SAFE_CALL (octave_history_write_timestamp, ());
+    if (! octave::command_history::ignoring_entries ())
+      OCTAVE_SAFE_CALL (octave::command_history::clean_up_and_save, ());
 
-        if (! octave::command_history::ignoring_entries ())
-          OCTAVE_SAFE_CALL (octave::command_history::clean_up_and_save, ());
+    OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ());
 
-        OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ());
+    OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ());
 
-        OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ());
+    OCTAVE_SAFE_CALL (close_files, ());
 
-        OCTAVE_SAFE_CALL (close_files, ());
+    OCTAVE_SAFE_CALL (cleanup_tmp_files, ());
 
-        OCTAVE_SAFE_CALL (cleanup_tmp_files, ());
+    OCTAVE_SAFE_CALL (symbol_table::cleanup, ());
 
-        OCTAVE_SAFE_CALL (symbol_table::cleanup, ());
+    OCTAVE_SAFE_CALL (sysdep_cleanup, ());
 
-        OCTAVE_SAFE_CALL (sysdep_cleanup, ());
+    OCTAVE_SAFE_CALL (octave_finalize_hdf5, ());
 
-        OCTAVE_SAFE_CALL (octave_finalize_hdf5, ());
-
-        OCTAVE_SAFE_CALL (octave::flush_stdout, ());
+    OCTAVE_SAFE_CALL (octave::flush_stdout, ());
 
-        // Don't call singleton_cleanup_list::cleanup until we have the
-        // problems with registering/unregistering types worked out.  For
-        // example, uncomment the following line, then use the make_int
-        // function from the examples directory to create an integer
-        // object and then exit Octave.  Octave should crash with a
-        // segfault when cleaning up the typinfo singleton.  We need some
-        // way to force new octave_value_X types that are created in
-        // .oct files to be unregistered when the .oct file shared library
-        // is unloaded.
-        //
-        // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ());
+    // Don't call singleton_cleanup_list::cleanup until we have the
+    // problems with registering/unregistering types worked out.  For
+    // example, uncomment the following line, then use the make_int
+    // function from the examples directory to create an integer
+    // object and then exit Octave.  Octave should crash with a
+    // segfault when cleaning up the typinfo singleton.  We need some
+    // way to force new octave_value_X types that are created in
+    // .oct files to be unregistered when the .oct file shared library
+    // is unloaded.
+    //
+    // OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ());
 
-        OCTAVE_SAFE_CALL (octave::chunk_buffer::clear, ());
-      }
+    OCTAVE_SAFE_CALL (octave::chunk_buffer::clear, ());
   }
 
   void interpreter::recover_from_exception (void)