diff --git a/libinterp/corefcn/interpreter.cc b/libinterp/corefcn/interpreter.cc --- a/libinterp/corefcn/interpreter.cc +++ b/libinterp/corefcn/interpreter.cc @@ -649,8 +649,136 @@ namespace octave OCTAVE_THREAD_LOCAL interpreter *interpreter::instance = nullptr; + // 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_action restore_debug_on_error \ + (&error_system::set_debug_on_error, &m_error_system, \ + m_error_system.debug_on_error ()); \ + \ + unwind_action restore_debug_on_warning \ + (&error_system::set_debug_on_warning, &m_error_system, \ + 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) + interpreter::~interpreter (void) { + if (! m_initialized) + return; + + // Set to false early in case we are called recursively. + m_initialized = false; + + OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0)); + + // If we are attached to a GUI, process pending events and + // disable the link. + + OCTAVE_SAFE_CALL (m_event_manager.process_events, (true)); + OCTAVE_SAFE_CALL (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. Each atexit function is executed with + // OCTAVE_SAFE_CALL, so we don't need that here. + + execute_atexit_fcns (); + + // Clear all functions and variables. + + // Note that we don't force symbols to be cleared, so we will + // respect mlock at this point. Later, we'll force all variables + // and functions to be cleared. + + OCTAVE_SAFE_CALL (clear_all, ()); + + // We may still have some figures. Close them. + + OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0)); + + // What is supposed to happen if a figure has a closerequestfcn or + // deletefcn callback registered that creates other figures or + // variables? What if those variables are classdef objects with + // destructors that can create figures? The possibilities are + // endless. At some point, we have to give up and force execution + // to end. + + // Note that we again don't force symbols to be cleared, so we + // continue to respect mlock here. Later, we'll force all variables + // and functions to be cleared. + + OCTAVE_SAFE_CALL (clear_all, ()); + + // 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_gtk_manager.unload_all_toolkits, ()); + + // Now that the graphics toolkits have been unloaded, force all + // symbols to be cleared. + + OCTAVE_SAFE_CALL (clear_all, (true)); + + // 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? + // What will happen if the destructor for an obect attempts to + // display a figure? + + OCTAVE_SAFE_CALL (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, ()); + delete m_gh_manager; } @@ -987,129 +1115,9 @@ namespace octave 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_action restore_debug_on_error \ - (&error_system::set_debug_on_error, &m_error_system, \ - m_error_system.debug_on_error ()); \ - \ - unwind_action restore_debug_on_warning \ - (&error_system::set_debug_on_warning, &m_error_system, \ - 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) { - OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0)); - - // If we are attached to a GUI, process pending events and - // disable the link. - - OCTAVE_SAFE_CALL (m_event_manager.process_events, (true)); - OCTAVE_SAFE_CALL (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. Each atexit function is executed with - // OCTAVE_SAFE_CALL, so we don't need that here. - - execute_atexit_fcns (); - - // Clear all functions and variables. - - // Note that we don't force symbols to be cleared, so we will - // respect mlock at this point. Later, we'll force all variables - // and functions to be cleared. - - OCTAVE_SAFE_CALL (clear_all, ()); - - // We may still have some figures. Close them. - - OCTAVE_SAFE_CALL (feval, ("close", ovl ("all"), 0)); - - // What is supposed to happen if a figure has a closerequestfcn or - // deletefcn callback registered that creates other figures or - // variables? What if those variables are classdef objects with - // destructors that can create figures? The possibilities are - // endless. At some point, we have to give up and force execution - // to end. - - // Note that we again don't force symbols to be cleared, so we - // continue to respect mlock here. Later, we'll force all variables - // and functions to be cleared. - - OCTAVE_SAFE_CALL (clear_all, ()); - - // 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_gtk_manager.unload_all_toolkits, ()); - - // Now that the graphics toolkits have been unloaded, force all - // symbols to be cleared. - - OCTAVE_SAFE_CALL (clear_all, (true)); - - // 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? - // What will happen if the destructor for an obect attempts to - // display a figure? - - OCTAVE_SAFE_CALL (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, ()); + // Do nothing. } void interpreter::execute_atexit_fcns (void)