From b6e7caf737d321016ebcdd465c8ba70c4291ed3f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 12 Dec 2016 01:49:11 +0100 Subject: [PATCH] Guistart(#1045): relocate opening of GuiNotification into the CoreServices up to now this happened from the GuiRunner, which was a rather bad idea - it can throw and thus interfer with the startup process - the GuiNotification can not sensibly be *implemented* just backed by the GuiRunner. While CoreService offers access to the necessary implementation facilities to do so --- src/backend/thread-wrapper.hpp | 6 ++-- src/common/guifacade.cpp | 8 ++++++ src/gui/ctrl/core-service.hpp | 3 ++ src/gui/guistart.cpp | 25 +++++++++-------- wiki/thinkPad.ichthyo.mm | 51 ++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 15 deletions(-) diff --git a/src/backend/thread-wrapper.hpp b/src/backend/thread-wrapper.hpp index 62e04d026..92957828e 100644 --- a/src/backend/thread-wrapper.hpp +++ b/src/backend/thread-wrapper.hpp @@ -62,7 +62,7 @@ namespace backend { * The new thread starts immediately within the ctor; after returning, the new * thread has already copied the arguments and indeed actively started to run. * - * \par Joining, cancellation and memory management + * # Joining, cancellation and memory management * In the basic version (class Thread), the created thread is completely detached * and not further controllable. There is no way to find out its execution state, * wait on termination or even cancel it. Client code needs to implement such @@ -77,7 +77,7 @@ namespace backend { * must join to prevent pulling away member variables the thread function will * continue to use. * - * \par failures in the thread function + * # failures in the thread function * The operation started in the new thread is protected by a top-level catch block. * Error states or caught exceptions can be propagated through the lumiera_error * state flag, when using the \c join() facility. By invoking \join().maybeThrow() @@ -86,7 +86,7 @@ namespace backend { * async Thread is considered a violation of policy and will result in emergency * shutdown of the whole application. * - * \par synchronisation barriers + * # synchronisation barriers * Lumiera threads provide a low-level synchronisation mechanism, which is used * to secure the hand-over of additional arguments to the thread function. It * can be used by client code, but care has to be taken to avoid getting out diff --git a/src/common/guifacade.cpp b/src/common/guifacade.cpp index 07e9b2f67..5509160f0 100644 --- a/src/common/guifacade.cpp +++ b/src/common/guifacade.cpp @@ -115,6 +115,14 @@ namespace gui { return true; } + /** + * @warning there is a possible race here, + * when shutdown is triggered before the GUI was able to open the GuiNotification interface. + * However, the Lumiera thread handling wrapper/framework ensures that a new thread actually + * starts to execute (and picks up the arguments), prior to returning from the thread starting + * function. For this reason, it is rather unlikely this race actually happens in practice, + * since opening the GuiNotification interface is done early, while starting the UI-Bus. + */ void triggerShutdown () noexcept override { diff --git a/src/gui/ctrl/core-service.hpp b/src/gui/ctrl/core-service.hpp index 62b91daf6..d16fd7f76 100644 --- a/src/gui/ctrl/core-service.hpp +++ b/src/gui/ctrl/core-service.hpp @@ -53,6 +53,7 @@ #include "lib/error.hpp" #include "include/logging.h" //#include "lib/idi/entry-id.hpp" +#include "gui/notification-service.hpp" #include "gui/ctrl/bus-term.hpp" #include "gui/ctrl/nexus.hpp" //#include "lib/util.hpp" @@ -89,6 +90,7 @@ namespace ctrl{ { Nexus uiBusBackbone_; + NotificationService activateNotificationService_; virtual void act (GenNode const& command) @@ -109,6 +111,7 @@ namespace ctrl{ CoreService (ID identity =lib::idi::EntryID()) : BusTerm(identity, uiBusBackbone_) , uiBusBackbone_{*this} + , activateNotificationService_() // opens the GuiNotification facade interface { INFO (gui, "UI-Backbone operative."); } diff --git a/src/gui/guistart.cpp b/src/gui/guistart.cpp index 96e46f898..5f7ca08fc 100644 --- a/src/gui/guistart.cpp +++ b/src/gui/guistart.cpp @@ -30,15 +30,16 @@ ** up the GUI. The loading and shutdown process is carried out by gui::GuiFacade and ** controlled by lumiera::AppState, which in turn is activated by Lumiera main(). ** - ** After successfully loading this module, a call to #kickOff is expected to be - ** issued, passing a termination signal (callback) to be executed when the GUI - ** terminates. The \c kickOff() call remains blocked within the main GTK event loop; - ** thus typically this call should be issued within a separate dedicated GUI thread. - ** Especially, the gui::GuiRunner will ensure this to happen. + ** After successfully loading this module, a call to GuiFacade::launchUI is expected to + ** happen, passing a termination signal (callback) to be executed when the GUI terminates. + ** The implementation of GuiFacade in the GuiRunner in fact issues this call from the ctor + ** body, while the interface is opened via an InstanceHandle member. The `launchUI()` call + ** starts a new thread, which then becomes the UI event thread and remains blocked within + ** the main GTK event loop. Before entering this loop, the CoreService of the GUI and + ** especially the [UI-Bus](\ref ui-bus.hpp) is started see \ref GtkLumiera::run. + ** This entails also to open the primary "business" interface(s) of the GUI + ** (currently as of 1/16 this is the interface gui::GuiNotification.) ** - ** Prior to entering the GTK event loop, all primary "business" interface of the GUI - ** will be opened (currently as of 1/09 this is the interface gui::GuiNotification.) - ** ** @see lumiera::AppState ** @see gui::GuiFacade ** @see guifacade.cpp @@ -54,7 +55,6 @@ #include "lib/error.hpp" #include "gui/guifacade.hpp" -#include "gui/notification-service.hpp" #include "gui/display-service.hpp" #include "common/subsys.hpp" #include "backend/thread-wrapper.hpp" @@ -85,17 +85,18 @@ namespace gui { /**************************************************************************//** * Implement the necessary steps for actually making the Lumiera Gui available. * Open the business interface(s) and start up the GTK GUI main event loop. + * @todo to ensure invocation of the termination signal, any members + * should be failsafe on initialisation (that means, we must no + * open other interfaces here...) ///////////////////////////TICKET #82 */ struct GuiLifecycle { string error_; Subsys::SigTerm& reportOnTermination_; - NotificationService activateNotificationService_; - DisplayService activateDisplayService_; + DisplayService activateDisplayService_; ///////////////////////////TICKET #82 will go away once we have a real OutputSlot offered by the UI GuiLifecycle (Subsys::SigTerm& terminationHandler) : reportOnTermination_(terminationHandler) - , activateNotificationService_() // opens the GuiNotification facade interface , activateDisplayService_() // opens the gui::Display facade interface { } diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 2d8fb1aae..6e6785161 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -153,6 +153,57 @@ + + + + + + + +

+ ...weil es dadurch passieren könnte, +

+

+ daß die Konstruktion des GuiRunners schon scheitert, bevor der Rumpf des ctors aufgerufen wird. +

+

+ In einem solchen Fall wird leider auch der Rumpf des dtors nicht aufgerufen, wodurch das +

+

+ Term-Signal nicht ausgesendet würde. +

+ + +
+ +
+ + + +
+ + + + + + + + + + +

+ ...weil unser Thread-Framework +

+

+ tatsächlich erzwingt, daß der neue Thrad zu laufen beginnt, bevor die +

+

+ startende Funktion zurückkehrt. +

+ + +
+