Mercurial > octave
diff libgui/src/interpreter-qobject.cc @ 27695:cdb681adc85a
improve exit behavior with qt graphics toolkit (bug #56952)
When I was able to reproduce it, the crash described in bug report
#56952 appeared to be happening when the Qt event loop was calling
QtHandles::qt_graphics_toolkit::create_object when the interpreter was
being deleted and the gh_manager object was already invalid, so
attempting to lock the mutex it contains lead to a segfault.
This change attempts to avoid that possibility by disabling the Qt
graphics toolkit when interpreter_qobject::execute is finished with
the interpreter. We also allow the the qt_application object to
delete the interpreter.
* interpreter-qobject.h, interpreter-qobject.cc
(interpreter_qobject::graphics_fini): New function.
(interpreter_qobject::execute): Use an unwind_action to ensure that
graphics_fini is called after the interpreter is finished executing
commands. Don't explicitly delete the interpreter. Allow the
application context to do that job.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 15 Nov 2019 10:37:33 -0500 |
parents | b3401292e101 |
children | 5e8891dceec7 |
line wrap: on
line diff
--- a/libgui/src/interpreter-qobject.cc Thu Nov 14 21:35:14 2019 -0500 +++ b/libgui/src/interpreter-qobject.cc Fri Nov 15 10:37:33 2019 -0500 @@ -36,6 +36,8 @@ #include "qt-graphics-toolkit.h" #include "qt-interpreter-events.h" +#include "unwind-prot.h" + #include "graphics.h" #include "gtk-manager.h" #include "input.h" @@ -54,6 +56,9 @@ qt_application& app_context = m_octave_qobj.app_context (); + // The application context will own the interpreter. It is + // responsible for cleaning it up when the application exits. + interpreter& interp = app_context.create_interpreter (); event_manager& evmgr = interp.get_event_manager (); @@ -79,8 +84,8 @@ if (interp.initialized ()) { - // The interpreter should be completely ready at this point so let - // the GUI know. + // The interpreter should be completely ready at this point + // so let the GUI know. m_interpreter = &interp; @@ -88,6 +93,14 @@ graphics_init (); + // We created the Qt graphics toolkit and interperter here. + // Disable and delete it when the interpreter is done + // executing commands for us. Use an unwind_action to + // ensure that it is disabled and deleted even if we exit + // this code block becuase an exception is thrown. + + unwind_action ([this] (void) { graphics_fini (); }); + // Start executing commands in the command window. exit_status = interp.execute (); @@ -102,11 +115,6 @@ m_interpreter = nullptr; - // Whether or not initialization succeeds we need to clean up the - // interpreter once we are done with it. - - app_context.delete_interpreter (); - emit octave_finished_signal (exit_status); } @@ -119,6 +127,9 @@ { #if defined (HAVE_QT_GRAPHICS) + if (! m_interpreter) + return; + gh_manager& gh_mgr = m_interpreter->get_gh_manager (); autolock guard (gh_mgr.graphics_lock ()); @@ -145,6 +156,26 @@ #endif } + void interpreter_qobject::graphics_fini (void) + { +#if defined (HAVE_QT_GRAPHICS) + + if (! m_interpreter) + return; + + octave::gtk_manager& gtk_mgr = m_interpreter->get_gtk_manager (); + + gtk_mgr.unregister_toolkit ("qt"); + + gtk_mgr.unload_toolkit ("qt"); + + delete m_graphics_toolkit; + + m_graphics_toolkit = nullptr; + +#endif + } + void interpreter_qobject::interpreter_event (const fcn_callback& fcn) { if (! m_interpreter)