changeset 28348:d73e4749d8dd

maint: Merge stable to default.
author John W. Eaton <jwe@octave.org>
date Fri, 22 May 2020 16:22:08 -0400
parents 40024b83597c (current diff) 00a9a49c7670 (diff)
children c6d10df71863
files libgui/src/octave-qobject.cc libinterp/corefcn/graphics.cc libinterp/corefcn/graphics.in.h
diffstat 11 files changed, 197 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/graphics/ObjectProxy.cc	Fri May 22 11:06:58 2020 +0200
+++ b/libgui/graphics/ObjectProxy.cc	Fri May 22 16:22:08 2020 -0400
@@ -55,6 +55,8 @@
           {
             disconnect (this, SIGNAL (sendUpdate (int)),
                         m_object, SLOT (slotUpdate (int)));
+            disconnect (this, SIGNAL (sendFinalize (void)),
+                        m_object, SLOT (slotFinalize (void)));
             disconnect (this, SIGNAL (sendRedraw (void)),
                         m_object, SLOT (slotRedraw (void)));
             disconnect (this, SIGNAL (sendShow (void)),
@@ -69,6 +71,8 @@
           {
             connect (this, SIGNAL (sendUpdate (int)),
                      m_object, SLOT (slotUpdate (int)));
+            connect (this, SIGNAL (sendFinalize (void)),
+                     m_object, SLOT (slotFinalize (void)));
             connect (this, SIGNAL (sendRedraw (void)),
                      m_object, SLOT (slotRedraw (void)));
             connect (this, SIGNAL (sendShow (void)),
@@ -90,24 +94,13 @@
   void
   ObjectProxy::update (int pId)
   {
-    if (octave::thread::is_thread ())
-      emit sendUpdate (pId);
-    else if (m_object)
-      m_object->slotUpdate (pId);
+    emit sendUpdate (pId);
   }
 
   void
   ObjectProxy::finalize (void)
   {
-    if (! m_object)
-      return;
-
-    Qt::ConnectionType t = Qt::BlockingQueuedConnection;
-
-    if (QThread::currentThread () == QCoreApplication::instance ()->thread ())
-      t = Qt::DirectConnection;
-
-    QMetaObject::invokeMethod (m_object, "slotFinalize", t);
+    emit sendFinalize ();
   }
 
   void
--- a/libgui/graphics/ObjectProxy.h	Fri May 22 11:06:58 2020 +0200
+++ b/libgui/graphics/ObjectProxy.h	Fri May 22 16:22:08 2020 -0400
@@ -56,6 +56,7 @@
 
   signals:
     void sendUpdate (int pId);
+    void sendFinalize (void);
     void sendRedraw (void);
     void sendShow (void);
     void sendPrint (const QString& file_cmd, const QString& term);
--- a/libgui/src/interpreter-qobject.cc	Fri May 22 11:06:58 2020 +0200
+++ b/libgui/src/interpreter-qobject.cc	Fri May 22 16:22:08 2020 -0400
@@ -78,7 +78,7 @@
 
             m_interpreter = &interp;
 
-            emit octave_ready_signal ();
+            emit ready ();
 
             graphics_init (interp, m_octave_qobj);
 
@@ -92,16 +92,31 @@
         exit_status = ex.exit_status ();
       }
 
-    // Disable events from being passed from the GUI to the interpreter.
+    // Signal that the interpreter is done executing code in the main
+    // REPL, from script files, or command line eval arguments.  By
+    // using a signal here, we give the GUI a chance to process any
+    // pending events, then signal that it is safe to shutdown the
+    // interpreter.  Our notification here allows the GUI to insert the
+    // request to shutdown the interpreter in the event queue after any
+    // other pending signals.  The application context owns the
+    // interpreter and will be responsible for deleting it later, when
+    // the application object destructor is executed.
 
-    m_interpreter = nullptr;
+    emit execution_finished (exit_status);
+  }
 
-    // Whether or not initialization succeeds we need to clean up the
-    // interpreter once we are done with it.
+  // This function is expected to be executed when the GUI signals that
+  // it is finished processing events and ready for the interpreter to
+  // perform shutdown actions.
 
-    app_context.delete_interpreter ();
+  void interpreter_qobject::shutdown (int exit_status)
+  {
+    if (m_interpreter)
+      m_interpreter->shutdown ();
 
-    emit octave_finished_signal (exit_status);
+    // Signal that the interpreter has executed shutdown actions.
+
+    emit shutdown_finished (exit_status);
   }
 
   void interpreter_qobject::interpreter_event (const fcn_callback& fcn)
--- a/libgui/src/interpreter-qobject.h	Fri May 22 11:06:58 2020 +0200
+++ b/libgui/src/interpreter-qobject.h	Fri May 22 16:22:08 2020 -0400
@@ -54,9 +54,11 @@
 
   signals:
 
-    void octave_ready_signal (void);
+    void ready (void);
 
-    void octave_finished_signal (int);
+    void execution_finished (int);
+
+    void shutdown_finished (int);
 
   public slots:
 
@@ -82,6 +84,8 @@
 
     void execute (void);
 
+    void shutdown (int);
+
   private:
 
     base_qobject& m_octave_qobj;
--- a/libgui/src/octave-qobject.cc	Fri May 22 11:06:58 2020 +0200
+++ b/libgui/src/octave-qobject.cc	Fri May 22 16:22:08 2020 -0400
@@ -200,8 +200,14 @@
     // Force left-to-right alignment (see bug #46204)
     m_qapplication->setLayoutDirection (Qt::LeftToRight);
 
-    connect (m_interpreter_qobj, SIGNAL (octave_finished_signal (int)),
-             this, SLOT (handle_octave_finished (int)));
+    connect (m_interpreter_qobj, SIGNAL (execution_finished (int)),
+             this, SLOT (handle_interpreter_execution_finished (int)));
+
+    connect (this, SIGNAL (request_interpreter_shutdown (int)),
+             m_interpreter_qobj, SLOT (shutdown (int)));
+
+    connect (m_interpreter_qobj, SIGNAL (shutdown_finished (int)),
+             this, SLOT (handle_interpreter_shutdown_finished (int)));
 
     connect (m_main_thread, SIGNAL (finished (void)),
              m_main_thread, SLOT (deleteLater (void)));
@@ -270,7 +276,12 @@
     return true;
   }
 
-  void base_qobject::handle_octave_finished (int exit_status)
+  void base_qobject::handle_interpreter_execution_finished (int exit_status)
+  {
+    emit request_interpreter_shutdown (exit_status);
+  }
+
+  void base_qobject::handle_interpreter_shutdown_finished (int exit_status)
   {
 #if defined (Q_OS_MAC)
     // fprintf to stderr is needed by macOS, for poorly-understood reasons.
@@ -342,7 +353,7 @@
   gui_qobject::gui_qobject (qt_application& app_context)
     : base_qobject (app_context), m_main_window (new main_window (*this))
   {
-    connect (m_interpreter_qobj, SIGNAL (octave_ready_signal (void)),
+    connect (m_interpreter_qobj, SIGNAL (ready (void)),
              m_main_window, SLOT (handle_octave_ready (void)));
 
     connect (qt_link (),
--- a/libgui/src/octave-qobject.h	Fri May 22 11:06:58 2020 +0200
+++ b/libgui/src/octave-qobject.h	Fri May 22 16:22:08 2020 -0400
@@ -127,9 +127,15 @@
 
     virtual bool confirm_shutdown (void);
 
+  signals:
+
+    void request_interpreter_shutdown (int);
+
   public slots:
 
-    void handle_octave_finished (int);
+    void handle_interpreter_execution_finished (int);
+
+    void handle_interpreter_shutdown_finished (int);
 
     void interpreter_event (const fcn_callback& fcn);
 
--- a/libinterp/corefcn/graphics-toolkit.cc	Fri May 22 11:06:58 2020 +0200
+++ b/libinterp/corefcn/graphics-toolkit.cc	Fri May 22 16:22:08 2020 -0400
@@ -54,4 +54,15 @@
 
     return initialize (go);
   }
+
+  void
+  base_graphics_toolkit::finalize (const graphics_handle& h)
+  {
+    gh_manager& gh_mgr
+      = octave::__get_gh_manager__ ("base_graphics_toolkit::finalize");
+
+    graphics_object go = gh_mgr.get_object (h);
+
+    finalize (go);
+  }
 }
--- a/libinterp/corefcn/graphics.cc	Fri May 22 11:06:58 2020 +0200
+++ b/libinterp/corefcn/graphics.cc	Fri May 22 16:22:08 2020 -0400
@@ -3207,17 +3207,6 @@
 
 // ---------------------------------------------------------------------
 
-void
-base_graphics_toolkit::finalize (const graphics_handle& h)
-{
-  gh_manager& gh_mgr
-    = octave::__get_gh_manager__ ("base_graphics_toolkit::finalize");
-
-  graphics_object go = gh_mgr.get_object (h);
-
-  finalize (go);
-}
-
 static int
 toggle_warn (std::string id, bool on, int state = -1)
 {
@@ -3359,7 +3348,7 @@
 }
 
 bool
-base_properties::has_dynamic_property (const std::string& pname)
+base_properties::has_dynamic_property (const std::string& pname) const
 {
   const std::set<std::string>& dynprops = dynamic_property_names ();
 
@@ -3386,7 +3375,7 @@
 }
 
 property
-base_properties::get_property_dynamic (const caseless_str& pname)
+base_properties::get_property_dynamic (const caseless_str& pname) const
 {
   std::map<caseless_str, property, cmp_caseless_str>::const_iterator it
     = all_props.find (pname);
--- a/libinterp/corefcn/graphics.in.h	Fri May 22 11:06:58 2020 +0200
+++ b/libinterp/corefcn/graphics.in.h	Fri May 22 16:22:08 2020 -0400
@@ -2233,6 +2233,9 @@
 
   virtual octave_value get (bool all = false) const;
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible with the way that properties are stored as
+  // specific types in the graphics_object classes.
   virtual property get_property (const caseless_str& pname);
 
   virtual bool has_property (const caseless_str&) const
@@ -2370,7 +2373,7 @@
 
   std::set<std::string> dynamic_property_names (void) const;
 
-  bool has_dynamic_property (const std::string& pname);
+  bool has_dynamic_property (const std::string& pname) const;
 
 protected:
   std::set<std::string> dynamic_properties;
@@ -2381,7 +2384,7 @@
 
   octave_value get_dynamic (bool all = false) const;
 
-  property get_property_dynamic (const caseless_str& pname);
+  property get_property_dynamic (const caseless_str& pname) const;
 
   BEGIN_BASE_PROPERTIES
     // properties common to all objects
@@ -2547,10 +2550,16 @@
     return base_properties::has_readonly_property (pname);
   }
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible.
   virtual std::string values_as_string (void);
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible.
   virtual std::string value_as_string (const std::string& prop);
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible.
   virtual octave_scalar_map values_as_struct (void);
 
   virtual graphics_handle get_parent (void) const
@@ -2796,13 +2805,19 @@
     return rep->has_readonly_property (pname);
   }
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible.
   std::string values_as_string (void) { return rep->values_as_string (); }
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible.
   std::string value_as_string (const std::string& prop)
   {
     return rep->value_as_string (prop);
   }
 
+  // FIXME: It seems like this function should be const, but that is
+  // currently not possible.
   octave_map values_as_struct (void) { return rep->values_as_struct (); }
 
   graphics_handle get_parent (void) const { return rep->get_parent (); }
--- a/libinterp/corefcn/interpreter.cc	Fri May 22 11:06:58 2020 +0200
+++ b/libinterp/corefcn/interpreter.cc	Fri May 22 16:22:08 2020 -0400
@@ -635,8 +635,6 @@
 
   interpreter::~interpreter (void)
   {
-    cleanup ();
-
     delete m_gh_manager;
   }
 
@@ -807,6 +805,114 @@
     return exit_status;
   }
 
+  // Call a function with exceptions handled to avoid problems with
+  // errors while shutting down.
+
+#define OCTAVE_IGNORE_EXCEPTION(E)                                      \
+  catch (E)                                                             \
+    {                                                                   \
+      recover_from_exception ();                                        \
+                                                                        \
+      std::cerr << "error: ignoring " #E " while preparing to exit"     \
+                << std::endl;                                           \
+    }
+
+#define OCTAVE_SAFE_CALL(F, ARGS)                                       \
+  do                                                                    \
+    {                                                                   \
+      try                                                               \
+        {                                                               \
+          unwind_protect frame;                                         \
+                                                                        \
+          frame.add_method (m_error_system,                             \
+                            &error_system::set_debug_on_error,          \
+                            m_error_system.debug_on_error ());          \
+          frame.add_method (m_error_system,                             \
+                            &error_system::set_debug_on_warning,        \
+                            m_error_system.debug_on_warning ());        \
+                                                                        \
+          m_error_system.debug_on_error (false);                        \
+          m_error_system.debug_on_warning (false);                      \
+                                                                        \
+          F ARGS;                                                       \
+        }                                                               \
+      OCTAVE_IGNORE_EXCEPTION (const exit_exception&)                   \
+      OCTAVE_IGNORE_EXCEPTION (const interrupt_exception&)              \
+      OCTAVE_IGNORE_EXCEPTION (const execution_exception&)              \
+      OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&)                   \
+    }                                                                   \
+  while (0)
+
+  void interpreter::shutdown (void)
+  {
+    // If we are attached to a GUI, process pending events and
+    // disable the link.
+
+    m_event_manager.process_events (true);
+    m_event_manager.disable ();
+
+    OCTAVE_SAFE_CALL (m_input_system.clear_input_event_hooks, ());
+
+    // Any atexit functions added after this function call won't be
+    // executed.
+
+    execute_atexit_fcns ();
+
+    // Do this explicitly so that destructors for mex file objects
+    // are called, so that functions registered with mexAtExit are
+    // called.
+    OCTAVE_SAFE_CALL (m_symbol_table.clear_mex_functions, ());
+
+    OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
+
+    OCTAVE_SAFE_CALL (m_history_system.write_timestamp, ());
+
+    if (! command_history::ignoring_entries ())
+      OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
+
+    OCTAVE_SAFE_CALL (m_gh_manager->close_all_figures, ());
+
+    m_gtk_manager.unload_all_toolkits ();
+
+    // FIXME:  May still need something like this to ensure that
+    // destructors for class objects will run properly.  Should that be
+    // done earlier?  Before or after atexit functions are executed?
+    m_symbol_table.cleanup ();
+
+    OCTAVE_SAFE_CALL (sysdep_cleanup, ());
+
+    OCTAVE_SAFE_CALL (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, ());
+  }
+
+  void interpreter::execute_atexit_fcns (void)
+  {
+    // Prevent atexit functions from adding new functions to the list.
+    m_executing_atexit = true;
+
+    while (! m_atexit_fcns.empty ())
+      {
+        std::string fcn = m_atexit_fcns.front ();
+
+        m_atexit_fcns.pop_front ();
+
+        OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0));
+
+        OCTAVE_SAFE_CALL (flush_stdout, ());
+      }
+  }
+
   void interpreter::display_startup_message (void) const
   {
     bool inhibit_startup_message = false;
@@ -1185,114 +1291,6 @@
     return exit_status;
   }
 
-  // Call a function with exceptions handled to avoid problems with
-  // errors while shutting down.
-
-#define OCTAVE_IGNORE_EXCEPTION(E)                                      \
-  catch (E)                                                             \
-    {                                                                   \
-      recover_from_exception ();                                        \
-                                                                        \
-      std::cerr << "error: ignoring " #E " while preparing to exit"     \
-                << std::endl;                                           \
-    }
-
-#define OCTAVE_SAFE_CALL(F, ARGS)                                       \
-  do                                                                    \
-    {                                                                   \
-      try                                                               \
-        {                                                               \
-          unwind_protect frame;                                         \
-                                                                        \
-          frame.add_method (m_error_system,                             \
-                            &error_system::set_debug_on_error,          \
-                            m_error_system.debug_on_error ());          \
-          frame.add_method (m_error_system,                             \
-                            &error_system::set_debug_on_warning,        \
-                            m_error_system.debug_on_warning ());        \
-                                                                        \
-          m_error_system.debug_on_error (false);                        \
-          m_error_system.debug_on_warning (false);                      \
-                                                                        \
-          F ARGS;                                                       \
-        }                                                               \
-      OCTAVE_IGNORE_EXCEPTION (const exit_exception&)                   \
-      OCTAVE_IGNORE_EXCEPTION (const interrupt_exception&)              \
-      OCTAVE_IGNORE_EXCEPTION (const execution_exception&)              \
-      OCTAVE_IGNORE_EXCEPTION (const std::bad_alloc&)                   \
-    }                                                                   \
-  while (0)
-
-  void interpreter::cleanup (void)
-  {
-    // If we are attached to a GUI, process pending events and
-    // disable the link.
-
-    m_event_manager.process_events (true);
-    m_event_manager.disable ();
-
-    OCTAVE_SAFE_CALL (m_input_system.clear_input_event_hooks, ());
-
-    // Any atexit functions added after this function call won't be
-    // executed.
-
-    execute_atexit_fcns ();
-
-    // Do this explicitly so that destructors for mex file objects
-    // are called, so that functions registered with mexAtExit are
-    // called.
-    OCTAVE_SAFE_CALL (m_symbol_table.clear_mex_functions, ());
-
-    OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
-
-    OCTAVE_SAFE_CALL (m_history_system.write_timestamp, ());
-
-    if (! command_history::ignoring_entries ())
-      OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
-
-    OCTAVE_SAFE_CALL (m_gh_manager->close_all_figures, ());
-
-    m_gtk_manager.unload_all_toolkits ();
-
-    // FIXME:  May still need something like this to ensure that
-    // destructors for class objects will run properly.  Should that be
-    // done earlier?  Before or after atexit functions are executed?
-    m_symbol_table.cleanup ();
-
-    OCTAVE_SAFE_CALL (sysdep_cleanup, ());
-
-    OCTAVE_SAFE_CALL (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, ());
-  }
-
-  void interpreter::execute_atexit_fcns (void)
-  {
-    // Prevent atexit functions from adding new functions to the list.
-    m_executing_atexit = true;
-
-    while (! m_atexit_fcns.empty ())
-      {
-        std::string fcn = m_atexit_fcns.front ();
-
-        m_atexit_fcns.pop_front ();
-
-        OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0));
-
-        OCTAVE_SAFE_CALL (flush_stdout, ());
-      }
-  }
-
   tree_evaluator& interpreter::get_evaluator (void)
   {
     return m_evaluator;
--- a/libinterp/corefcn/interpreter.h	Fri May 22 11:06:58 2020 +0200
+++ b/libinterp/corefcn/interpreter.h	Fri May 22 16:22:08 2020 -0400
@@ -153,6 +153,8 @@
 
     int execute (void);
 
+    void shutdown (void);
+
     bool interactive (void) const
     {
       return m_interactive;
@@ -491,8 +493,6 @@
 
     int main_loop (void);
 
-    void cleanup (void);
-
     void execute_atexit_fcns (void);
 
     application *m_app_context;