# HG changeset patch # User John W. Eaton # Date 1590178928 14400 # Node ID d73e4749d8dd2cd8cd55852809f4c2306786488a # Parent 40024b83597cac3a2abf5820a335bc87eddb8124# Parent 00a9a49c7670a5b3ce881ea6de75200eb22be1ac maint: Merge stable to default. diff -r 40024b83597c -r d73e4749d8dd libgui/graphics/ObjectProxy.cc --- 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 diff -r 40024b83597c -r d73e4749d8dd libgui/graphics/ObjectProxy.h --- 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); diff -r 40024b83597c -r d73e4749d8dd libgui/src/interpreter-qobject.cc --- 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) diff -r 40024b83597c -r d73e4749d8dd libgui/src/interpreter-qobject.h --- 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; diff -r 40024b83597c -r d73e4749d8dd libgui/src/octave-qobject.cc --- 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 (), diff -r 40024b83597c -r d73e4749d8dd libgui/src/octave-qobject.h --- 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); diff -r 40024b83597c -r d73e4749d8dd libinterp/corefcn/graphics-toolkit.cc --- 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); + } } diff -r 40024b83597c -r d73e4749d8dd libinterp/corefcn/graphics.cc --- 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& 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::const_iterator it = all_props.find (pname); diff -r 40024b83597c -r d73e4749d8dd libinterp/corefcn/graphics.in.h --- 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 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 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 (); } diff -r 40024b83597c -r d73e4749d8dd libinterp/corefcn/interpreter.cc --- 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; diff -r 40024b83597c -r d73e4749d8dd libinterp/corefcn/interpreter.h --- 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;