# HG changeset patch # User John W. Eaton # Date 1365563304 14400 # Node ID 8b783661e03f8089dd162fa1fc4cbd42d11ea448 # Parent fa842e78f49132bf5900dd36e7985032283d6afc improve exit sequence for GUI * octave-link.h, octave-link.cc (octave_link::accepting_events): Delete variable and all uses. (octave_link::link_enabled): New data member. (octave_link::octave_link): Don't set octave_exit. Initialize link_enabled. (octave_link::do_exit): Delete definition. Now pure virtual. Return bool. (octave_link::exit): Call instance->do_exit. (octave_link::enabled): New function. (ocave_link::process_events): New arg, disable. Optionally disable event processing. Use octave_link::enabled instead of instance_ok everywhere except for octave_link::exit. (octave_link::cleanup_instance): Delete. * octave-qt-link.h, octave-qt-link.cc (octave_qt_link::octave_qt_link): Accept thread as argument. Don't connect main_thread::finished signal. (octave_qt_link::~octave_qt_link): Don't delete main_thread. (octave_qt_link::do_exit): Emit exit_signal and return true. (octave_qt_link::exit_signal: New signal. (octave_qt_link::void octave_thread_finished_signal): Delete. * main-window.h, main-window.cc (main_window::_octave_main_thread): New member variable. (main_window::main_window): Initialize _octave_main_thread and _octave_qt_link to 0. (main_window::~main_window): Don't call octave_link::connect_link. Delete _octave_main_thread. (main_window::exit): Accept exit status as argument and call QApplication::exit instead of quit. (main_window::construct): Don't connect qApp::aboutToQuit to main_window::prepare_to_exit. (main_window::construct_octave_qt_link): Create _octave_main_thread and pass to _octave_qt_link. Don't connect _octave_qt_link::octave_thread_finished to main_window::exit. Connect _octave_qt_link::exit_signal to main_window::exit. * toplev.h, toplev.cc (main_loop): If quitting_gracefully, just return exit status instead of calling clean_up_and_exit. (do_octave_atexit): Now static. Call octave_link::process_events with disable arg set to true. (octave_atexit_functions): Now static. (clean_up_and_exit): New argument, safe_to_return. Call octave_link::exit and possibly return or wait for octave_link::exit to terminate the process. * octave.cc (octave_execute_interpreter): Don't alter return value from main_loop. Pass safe_to_return = true to clean_up_and_exit. Return retval instead of 0. (octave_initialize_interpreter): Don't call atexit. diff --git a/libgui/src/main-window.cc b/libgui/src/main-window.cc --- a/libgui/src/main-window.cc +++ b/libgui/src/main-window.cc @@ -70,7 +70,9 @@ file_browser_window (new files_dock_widget (this)), doc_browser_window (new documentation_dock_widget (this)), editor_window (create_default_editor (this)), - workspace_window (new workspace_view (this)) + workspace_window (new workspace_view (this)), + _octave_main_thread (0), + _octave_qt_link (0) { // We have to set up all our windows, before we finally launch octave. construct (); @@ -78,23 +80,18 @@ main_window::~main_window (void) { -+ // Destroy the terminal first so that STDERR stream is redirected back -+ // to its original pipe to capture error messages at exit. + // Destroy the terminal first so that STDERR stream is redirected back + // to its original pipe to capture error messages at exit. delete command_window; - delete _workspace_model; - delete status_bar; - delete history_window; - delete file_browser_window; - delete doc_browser_window; + delete workspace_window; delete editor_window; - delete workspace_window; - - // Clean up all dynamically created objects to ensure they are - // deleted before this main_window is. Otherwise, some will be - // attached to a non-existent parent. - - octave_link::connect_link (0); + delete doc_browser_window; + delete file_browser_window; + delete history_window; + delete status_bar; + delete _workspace_model; + delete _octave_main_thread; delete _octave_qt_link; } @@ -266,9 +263,9 @@ } void -main_window::exit (void) +main_window::exit (int status) { - qApp->quit (); + qApp->exit (status); } void @@ -545,9 +542,6 @@ construct_tool_bar (); - connect (qApp, SIGNAL (aboutToQuit ()), - this, SLOT (prepare_to_exit ())); - connect (this, SIGNAL (settings_changed (const QSettings *)), this, SLOT (notice_settings (const QSettings *))); @@ -592,10 +586,12 @@ void main_window::construct_octave_qt_link (void) { - _octave_qt_link = new octave_qt_link (); + _octave_main_thread = new octave_main_thread (); - connect (_octave_qt_link, SIGNAL (octave_thread_finished ()), - this, SLOT (exit ())); + _octave_qt_link = new octave_qt_link (_octave_main_thread); + + connect (_octave_qt_link, SIGNAL (exit_signal (int)), + this, SLOT (exit (int))); connect (_octave_qt_link, SIGNAL (set_workspace_signal diff --git a/libgui/src/main-window.h b/libgui/src/main-window.h --- a/libgui/src/main-window.h +++ b/libgui/src/main-window.h @@ -92,7 +92,7 @@ void show_about_octave (void); void notice_settings (const QSettings *settings); void prepare_to_exit (void); - void exit (void); + void exit (int status); void reset_windows (void); void change_directory (const QString& dir); @@ -206,6 +206,8 @@ static const int current_directory_max_count = 16; QLineEdit *_current_directory_line_edit; + octave_main_thread *_octave_main_thread; + octave_qt_link *_octave_qt_link; // Flag for closing whole application. diff --git a/libgui/src/octave-qt-link.cc b/libgui/src/octave-qt-link.cc --- a/libgui/src/octave-qt-link.cc +++ b/libgui/src/octave-qt-link.cc @@ -34,17 +34,11 @@ #include "octave-qt-link.h" -octave_qt_link::octave_qt_link (void) - : octave_link (), main_thread (new octave_main_thread) -{ - connect (main_thread, SIGNAL (finished ()), - this, SIGNAL (octave_thread_finished ())); -} +octave_qt_link::octave_qt_link (octave_main_thread *mt) + : octave_link (), main_thread (mt) +{ } -octave_qt_link::~octave_qt_link (void) -{ - delete main_thread; -} +octave_qt_link::~octave_qt_link (void) { } void octave_qt_link::execute_interpreter (void) @@ -53,6 +47,14 @@ } bool +octave_qt_link::do_exit (int status) +{ + emit exit_signal (status); + + return true; +} + +bool octave_qt_link::do_edit_file (const std::string& file) { emit edit_file_signal (QString::fromStdString (file)); diff --git a/libgui/src/octave-qt-link.h b/libgui/src/octave-qt-link.h --- a/libgui/src/octave-qt-link.h +++ b/libgui/src/octave-qt-link.h @@ -49,12 +49,14 @@ public: - octave_qt_link (void); + octave_qt_link (octave_main_thread *mt); ~octave_qt_link (void); void execute_interpreter (void); + bool do_exit (int status); + bool do_edit_file (const std::string& file); void do_change_directory (const std::string& dir); @@ -91,6 +93,8 @@ signals: + void exit_signal (int status); + void edit_file_signal (const QString& file); void change_directory_signal (const QString& dir); @@ -115,8 +119,6 @@ void insert_debugger_pointer_signal (const QString&, int); void delete_debugger_pointer_signal (const QString&, int); - - void octave_thread_finished (void); }; #endif diff --git a/libinterp/interpfcn/octave-link.cc b/libinterp/interpfcn/octave-link.cc --- a/libinterp/interpfcn/octave-link.cc +++ b/libinterp/interpfcn/octave-link.cc @@ -50,11 +50,9 @@ octave_link::octave_link (void) : event_queue_mutex (new octave_mutex ()), gui_event_queue (), - debugging (false), accepting_events (true) + debugging (false), link_enabled (true) { command_editor::add_event_hook (octave_readline_hook); - - octave_exit = octave_link::exit; } // OBJ should be an object of a class that is derived from the base @@ -95,20 +93,6 @@ event_queue_mutex->unlock (); } -void -octave_link::do_exit (int) -{ - accepting_events = false; - - do_process_events (); -} - -bool -octave_link::instance_ok (void) -{ - return instance != 0; -} - DEFUN (__octave_link_edit_file__, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} __octave_link_edit_file__ (@var{file})\n\ diff --git a/libinterp/interpfcn/octave-link.h b/libinterp/interpfcn/octave-link.h --- a/libinterp/interpfcn/octave-link.h +++ b/libinterp/interpfcn/octave-link.h @@ -53,118 +53,130 @@ static void generate_events (void) { - if (instance_ok ()) + if (enabled ()) instance->do_generate_events (); } - static void process_events (void) + // If disable is TRUE, then no additional events will be processed + // other than exit. + + static void process_events (bool disable = false) { - if (instance_ok ()) - instance->do_process_events (); + if (enabled ()) + { + if (disable) + instance->link_enabled = false; + + instance->do_process_events (); + } } static void discard_events (void) { - if (instance_ok ()) + if (enabled ()) instance->do_discard_events (); } - static void exit (int status) + static bool exit (int status) { + bool retval = false; + if (instance_ok ()) - instance->do_exit (status); + retval = instance->do_exit (status); + + return retval; } template static void post_event (T *obj, void (T::*method) (void)) { - if (instance_ok ()) + if (enabled ()) instance->do_post_event (obj, method); } template static void post_event (T *obj, void (T::*method) (A), A arg) { - if (instance_ok ()) + if (enabled ()) instance->do_post_event (obj, method, arg); } template static void post_event (T *obj, void (T::*method) (const A&), const A& arg) { - if (instance_ok ()) + if (enabled ()) instance->do_post_event (obj, method, arg); } static void entered_readline_hook (void) { - if (instance_ok ()) + if (enabled ()) instance->do_entered_readline_hook (); } static void finished_readline_hook (void) { - if (instance_ok ()) + if (enabled ()) instance->do_finished_readline_hook (); } static bool edit_file (const std::string& file) { - return instance_ok () ? instance->do_edit_file (file) : false; + return enabled () ? instance->do_edit_file (file) : false; } static void change_directory (const std::string& dir) { - if (instance_ok ()) + if (enabled ()) instance->do_change_directory (dir); } static void set_workspace (const std::list& ws) { - if (instance_ok ()) + if (enabled ()) instance->do_set_workspace (ws); } static void clear_workspace (void) { - if (instance_ok ()) + if (enabled ()) instance->do_clear_workspace (); } static void set_history (const string_vector& hist) { - if (instance_ok ()) + if (enabled ()) instance->do_set_history (hist); } static void append_history (const std::string& hist_entry) { - if (instance_ok ()) + if (enabled ()) instance->do_append_history (hist_entry); } static void clear_history (void) { - if (instance_ok ()) + if (enabled ()) instance->do_clear_history (); } static void pre_input_event (void) { - if (instance_ok ()) + if (enabled ()) instance->do_pre_input_event (); } static void post_input_event (void) { - if (instance_ok ()) + if (enabled ()) instance->do_post_input_event (); } static void enter_debugger_event (const std::string& file, int line) { - if (instance_ok ()) + if (enabled ()) { instance->debugging = true; @@ -174,13 +186,13 @@ static void execute_in_debugger_event (const std::string& file, int line) { - if (instance_ok ()) + if (enabled ()) instance->do_execute_in_debugger_event (file, line); } static void exit_debugger_event (void) { - if (instance_ok () && instance->debugging) + if (enabled () && instance->debugging) { instance->debugging = false; @@ -191,7 +203,7 @@ static void update_breakpoint (bool insert, const std::string& file, int line) { - if (instance_ok ()) + if (enabled ()) instance->do_update_breakpoint (insert, file, line); } @@ -201,15 +213,18 @@ static octave_link *instance; - static void cleanup_instance (void) { delete instance; instance = 0; } - // No copying! octave_link (const octave_link&); octave_link& operator = (const octave_link&); - static bool instance_ok (void); + static bool instance_ok (void) { return instance != 0; } + + static bool enabled (void) + { + return instance_ok () ? instance->link_enabled : false; + } protected: @@ -220,39 +235,35 @@ event_queue gui_event_queue; bool debugging; - - bool accepting_events; + bool link_enabled; void do_generate_events (void); void do_process_events (void); void do_discard_events (void); - void do_exit (int status); - template void do_post_event (T *obj, void (T::*method) (void)) { - if (accepting_events) - gui_event_queue.add_method (obj, method); + gui_event_queue.add_method (obj, method); } template void do_post_event (T *obj, void (T::*method) (A), A arg) { - if (accepting_events) - gui_event_queue.add_method (obj, method, arg); + gui_event_queue.add_method (obj, method, arg); } template void do_post_event (T *obj, void (T::*method) (const A&), const A& arg) { - if (accepting_events) - gui_event_queue.add_method (obj, method, arg); + gui_event_queue.add_method (obj, method, arg); } void do_entered_readline_hook (void) { } void do_finished_readline_hook (void) { } + virtual bool do_exit (int status) = 0; + virtual bool do_edit_file (const std::string& file) = 0; virtual void do_change_directory (const std::string& dir) = 0; diff --git a/libinterp/interpfcn/toplev.cc b/libinterp/interpfcn/toplev.cc --- a/libinterp/interpfcn/toplev.cc +++ b/libinterp/interpfcn/toplev.cc @@ -57,6 +57,7 @@ #include "graphics.h" #include "input.h" #include "lex.h" +#include "octave-link.h" #include "oct-conf.h" #include "oct-conf-features.h" #include "oct-hist.h" @@ -614,10 +615,7 @@ recover_from_exception (); octave_stdout << "\n"; if (quitting_gracefully) - { - clean_up_and_exit (exit_status); - break; // If user has overriden the exit func. - } + return exit_status; } catch (octave_execution_exception) { @@ -641,13 +639,120 @@ // Fix up things before exiting. +static std::list octave_atexit_functions; + +static void +do_octave_atexit (void) +{ + static bool deja_vu = false; + + OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ()); + + while (! octave_atexit_functions.empty ()) + { + std::string fcn = octave_atexit_functions.front (); + + octave_atexit_functions.pop_front (); + + OCTAVE_SAFE_CALL (reset_error_handler, ()); + + OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + } + + if (! deja_vu) + { + deja_vu = true; + + // Process pending events and disasble octave_link event + // processing with this call. + + octave_link::process_events (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, ()); + + OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); + + // FIXME -- is this needed? Can it cause any trouble? + OCTAVE_SAFE_CALL (raw_mode, (0)); + + OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); + + if (! command_history::ignoring_entries ()) + OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); + + OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); + + OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); + + OCTAVE_SAFE_CALL (close_files, ()); + + OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); + + OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); + + OCTAVE_SAFE_CALL (sysdep_cleanup, ()); + + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); + + if (! quitting_gracefully && (interactive || forced_interactive)) + { + octave_stdout << "\n"; + + // Yes, we want this to be separate from the call to + // flush_octave_stdout above. + + OCTAVE_SAFE_CALL (flush_octave_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, ()); + + OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); + } +} + void -clean_up_and_exit (int retval) +clean_up_and_exit (int retval, bool safe_to_return) { do_octave_atexit (); - if (octave_exit) - (*octave_exit) (retval == EOF ? 0 : retval); + if (octave_link::exit (retval)) + { + if (safe_to_return) + return; + else + { + // What should we do here? We might be called from some + // location other than the end of octave_execute_interpreter, + // so it might not be safe to return. + + // We have nothing else to do at this point, and the + // octave_link::exit function is supposed to take care of + // exiting for us. Assume that job won't take more than a + // day... + + gnulib::sleep (86400); + } + } + else + { + if (octave_exit) + (*octave_exit) (retval == EOF ? 0 : retval); + } } DEFUN (quit, args, , @@ -992,89 +1097,6 @@ %!error system (1, 2, 3) */ -// FIXME -- this should really be static, but that causes -// problems on some systems. -std::list octave_atexit_functions; - -void -do_octave_atexit (void) -{ - static bool deja_vu = false; - - OCTAVE_SAFE_CALL (remove_input_event_hook_functions, ()); - - while (! octave_atexit_functions.empty ()) - { - std::string fcn = octave_atexit_functions.front (); - - octave_atexit_functions.pop_front (); - - OCTAVE_SAFE_CALL (reset_error_handler, ()); - - OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); - - OCTAVE_SAFE_CALL (flush_octave_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, ()); - - OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); - - // FIXME -- is this needed? Can it cause any trouble? - OCTAVE_SAFE_CALL (raw_mode, (0)); - - OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); - - if (! command_history::ignoring_entries ()) - OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); - - OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); - - OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); - - OCTAVE_SAFE_CALL (close_files, ()); - - OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); - - OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); - - OCTAVE_SAFE_CALL (sysdep_cleanup, ()); - - OCTAVE_SAFE_CALL (flush_octave_stdout, ()); - - if (! quitting_gracefully && (interactive || forced_interactive)) - { - octave_stdout << "\n"; - - // Yes, we want this to be separate from the call to - // flush_octave_stdout above. - - OCTAVE_SAFE_CALL (flush_octave_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, ()); - - OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); - } -} - void octave_add_atexit_function (const std::string& fname) { diff --git a/libinterp/interpfcn/toplev.h b/libinterp/interpfcn/toplev.h --- a/libinterp/interpfcn/toplev.h +++ b/libinterp/interpfcn/toplev.h @@ -52,16 +52,13 @@ extern OCTINTERP_API int exit_status; extern OCTINTERP_API void -clean_up_and_exit (int); +clean_up_and_exit (int status, bool safe_to_return = false); extern OCTINTERP_API void recover_from_exception (void); extern OCTINTERP_API int main_loop (void); extern OCTINTERP_API void -do_octave_atexit (void); - -extern OCTINTERP_API void octave_add_atexit_function (const std::string& fname); extern OCTINTERP_API bool diff --git a/libinterp/octave.cc b/libinterp/octave.cc --- a/libinterp/octave.cc +++ b/libinterp/octave.cc @@ -891,12 +891,6 @@ if (no_window_system) display_info::no_window_system (); - // Make sure we clean up when we exit. Also allow users to register - // functions. If we don't have atexit or on_exit, we're going to - // leave some junk files around if we exit abnormally. - - atexit (do_octave_atexit); - // Is input coming from a terminal? If so, we are probably // interactive. @@ -1008,14 +1002,11 @@ int retval = main_loop (); - if (retval == 1 && ! error_state) - retval = 0; - quitting_gracefully = true; - clean_up_and_exit (retval); + clean_up_and_exit (retval, true); - return 0; + return retval; } static bool