From 75b97ff9ddd6195aaccd04a748e183b8eb9babc8 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 3 Dec 2008 07:43:45 +0100 Subject: [PATCH] WIP draft remainder of the global start/stop sequence, incl errorhandling --- src/include/lifecycle.h | 3 + src/lumiera/appstate.cpp | 135 +++++++++++++++++++++++++------- src/lumiera/appstate.hpp | 11 +-- src/lumiera/lumiera.c | 66 ---------------- src/lumiera/lumiera.h | 57 -------------- src/lumiera/lumiera_init.c | 69 ---------------- src/lumiera/main.cpp | 4 +- src/lumiera/subsystemrunner.hpp | 2 + 8 files changed, 120 insertions(+), 227 deletions(-) delete mode 100644 src/lumiera/lumiera.c delete mode 100644 src/lumiera/lumiera.h delete mode 100644 src/lumiera/lumiera_init.c diff --git a/src/include/lifecycle.h b/src/include/lifecycle.h index b5b223f0b..b91ce5619 100644 --- a/src/include/lifecycle.h +++ b/src/include/lifecycle.h @@ -50,6 +50,9 @@ namespace lumiera { extern Symbol ON_GLOBAL_INIT; ///< to be triggered in main() @note no magic! extern Symbol ON_GLOBAL_SHUTDOWN; ///< to be triggered at the end of main() @note no magic! + extern Symbol ON_EMERGENCY; ///< activated on shutdown after premature failure of a subsystem + + // client code is free to register and use additional lifecycle events diff --git a/src/lumiera/appstate.cpp b/src/lumiera/appstate.cpp index c1e150311..67c96a3ae 100644 --- a/src/lumiera/appstate.cpp +++ b/src/lumiera/appstate.cpp @@ -35,20 +35,25 @@ extern "C" { #include "lumiera/plugin.h" } -//#include "common/util.hpp" +#include "common/util.hpp" #include "include/configfacade.hpp" //////////TODO: temp hack to force configfacade.o to be linked in +using util::cStr; -//using util::isnil; namespace lumiera { + namespace { // implementation details + + inline void + log_and_clear_unexpected_errorstate () + { + if (const char * errorstate = lumiera_error ()) + ERROR (NOBUG_ON, "*** Unexpected error: %s\n Triggering emergency exit.", errorstate); + } } - Symbol ON_BASIC_INIT ("ON_BASIC_INIT"); - Symbol ON_GLOBAL_INIT ("ON_GLOBAL_INIT"); - Symbol ON_GLOBAL_SHUTDOWN ("ON_GLOBAL_SHUTDOWN"); /** perform initialisation triggered on first access. @@ -63,14 +68,13 @@ namespace lumiera { */ AppState::AppState() : lifecycleHooks_(new LifecycleRegistry), - parts_(0) + subsystems_(0), + emergency_(false) { lifecycleHooks_->execute (ON_BASIC_INIT); // note in most cases a NOP } - AppState::~AppState() { } - AppState& @@ -93,22 +97,13 @@ namespace lumiera { - // ==== implementation startup sequence for main() ======= - struct SubsystemRunner - { - Option& opts_; - - SubsystemRunner (Option& opts) - : opts_(opts) - { } - - }; + // ===== Implementation startup and shutdown sequence for main() ======== #define _THROW_IF \ if (lumiera_error_peek()) \ - throw error::Fatal (lumiera_error()); + throw error::Fatal (lumiera_error()); @@ -131,16 +126,18 @@ namespace lumiera { _THROW_IF - parts_.reset (new SubsystemRunner (options)); + subsystems_.reset (new SubsystemRunner (options)); TRACE (lumiera, "Lumiera core started successfully."); } void - AppState::maybeStart (lumiera::Subsys&) + AppState::maybeStart (lumiera::Subsys& subsys) { - UNIMPLEMENTED ("maybe register and activate the given subsystem"); + TRACE (lumiera, "maybe startup %s...?", cStr(subsys)); + ASSERT (subsystems_); + subsystems_->maybeRun (subsys); } @@ -148,10 +145,40 @@ namespace lumiera { typedef AppState::ExitCode ExitCode; + /** @par + * This function is executed at the end of main(), after the necessary subsystems + * have been started, typically in separate threads. Thus, the main thread will + * enter a blocking wait, until all activated subsystems have signalled shutdown. + * After returning, we can proceed with the normal shutdown sequence. + * + * The SubsystemRunner ensures that in case of a premature failure of one subsystem, + * the termination of all other subsystems is initiated; when detecting this case, + * the emergency exit sequence is called. Any error which can't be handled within + * this scheme, should be thrown as exception, in which case the abort handler + * is activated. + */ ExitCode AppState::maybeWait() { - UNIMPLEMENTED ("wait on termination and normal shutdown"); + if (subsystems_) + { + emergency_ |= subsystems_->wait(); + subsystems_.reset(0); + } + + NOTICE (lumiera, "Shutting down Lumiera..."); + + if (emergency_) + { + ERROR (operate, "Triggering emergency exit..."); + lifecycle (ON_EMERGENCY); + return CLEAN_EMERGENCY_EXIT; + } + else + { + lifecycle (ON_GLOBAL_SHUTDOWN); + return NORMAL_EXIT; + } } @@ -159,23 +186,66 @@ namespace lumiera { ExitCode AppState::abort (lumiera::Error& problem) { - + INFO (operate, "Address of Config Facade = %x", &lumiera::Config::instance()); //////////TODO: a temp hack to force configfacade.cpp to be linked into lumiera.exe - - UNIMPLEMENTED ("clean error shutdown"); + + ERROR (operate, "Aborting Lumiera after unhandled error: %s", cStr(problem.what())); + + log_and_clear_unexpected_errorstate(); + + try + { + if (subsystems_) subsystems_->shutdownAll(); + return maybeWait (); + } + catch (...) + { + return abort(); + } } ExitCode - AppState::abort () + AppState::abort () throw() { - UNIMPLEMENTED ("emergency shutdown"); + log_and_clear_unexpected_errorstate(); + + if (emergency_) + { + lifecycle (ON_EMERGENCY); + return FAILED_EMERGENCY_EXIT; + } + else + { + lifecycle (ON_GLOBAL_SHUTDOWN); + return CLEAN_EXIT_AFTER_ERROR; + } } + /** anything which should be closed as late as possible and after + * the normal shutdown sequence can be placed into the AppState dtor. + * But note though, when the application is halted unconditionally, + * not dtors will be executed. + */ + AppState::~AppState() + { + try + { + TRACE (lumiera, "shutting down basic application layer..."); + lumiera_config_interface_destroy (); + lumiera_interfaceregistry_destroy (); + } + catch (...) + { + log_and_clear_unexpected_errorstate(); + } } + + + @@ -210,6 +280,13 @@ namespace lumiera { + Symbol ON_BASIC_INIT ("ON_BASIC_INIT"); + Symbol ON_GLOBAL_INIT ("ON_GLOBAL_INIT"); + Symbol ON_GLOBAL_SHUTDOWN ("ON_GLOBAL_SHUTDOWN"); + + Symbol ON_EMERGENCY ("ON_EMERGENCY"); + + } // namespace lumiera @@ -220,6 +297,8 @@ extern "C" { /* ==== implementation C interface for lifecycle hooks ======= */ extern const char * lumiera_ON_GLOBAL_INIT = lumiera::ON_GLOBAL_INIT; extern const char * lumiera_ON_GLOBAL_SHUTDOWN = lumiera::ON_GLOBAL_SHUTDOWN; + extern const char * lumiera_ON_EMERGENCY = lumiera::ON_EMERGENCY; + void diff --git a/src/lumiera/appstate.hpp b/src/lumiera/appstate.hpp index 017f896c8..3a9300583 100644 --- a/src/lumiera/appstate.hpp +++ b/src/lumiera/appstate.hpp @@ -68,7 +68,7 @@ namespace lumiera { private: AppState (); - ~AppState (); ///< deletion prohibited + ~AppState (); friend void boost::checked_delete(AppState*); @@ -85,8 +85,7 @@ namespace lumiera { /** evaluate the result of option parsing and maybe additional configuration * such as to be able to determine the further behaviour of the application. - * Set the internal state within this object accordingly. - * @return the AppState singleton instance */ + * Set the internal state within this object accordingly. */ void init (lumiera::Option& options); @@ -119,7 +118,7 @@ namespace lumiera { /** initiate an fatal emergency shutdown, * caused by an unforeseen error condition */ - ExitCode abort (); + ExitCode abort () throw(); @@ -128,7 +127,9 @@ namespace lumiera { typedef scoped_ptr PSub; PLife lifecycleHooks_; - PSub parts_; + PSub subsystems_; + + bool emergency_; friend class LifecycleHook; diff --git a/src/lumiera/lumiera.c b/src/lumiera/lumiera.c deleted file mode 100644 index 1e3c57597..000000000 --- a/src/lumiera/lumiera.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - lumiera.c - Lumiera main application shell - - Copyright (C) Lumiera.org - 2008, Christian Thaeter - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -//TODO: Support library includes// - - -//TODO: Lumiera header includes// -#include "include/nobugcfg.h" -#include "lumiera/lumiera.h" -#include "lumiera/interface.h" -#include "lumiera/interfaceregistry.h" -#include "lumiera/plugin.h" - -//TODO: internal/static forward declarations// - - -//TODO: System includes// -#include - - - -/** - * @file - * - */ - - -//code goes here// -int -start (int argc, char** argv) -{ - (void) argc; - (void) argv; - - - TRACE (lumiera, "initiating shutdown sequence"); - lumiera_shutdown (); - lumiera_interfaceregistry_destroy (); -} - - -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/src/lumiera/lumiera.h b/src/lumiera/lumiera.h deleted file mode 100644 index ecc4cd489..000000000 --- a/src/lumiera/lumiera.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - lumiera.h - Lumiera main application shell - - Copyright (C) Lumiera.org - 2008, Christian Thaeter - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef LUMIERA_LUMIERA_H -#define LUMIERA_LUMIERA_H - -//TODO: Support library includes// - - -//TODO: Forward declarations// - - -//TODO: Lumiera header includes// - - -//TODO: System includes// -#include - - - -/** - * @file - * - */ - -//TODO: declarations go here// - -void -lumiera_shutdown (void); - - -#endif -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/src/lumiera/lumiera_init.c b/src/lumiera/lumiera_init.c deleted file mode 100644 index bb6310855..000000000 --- a/src/lumiera/lumiera_init.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - lumiera_init.c - Lumiera initialization and shutdowen and global state - - Copyright (C) Lumiera.org - 2008, Christian Thaeter - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -//TODO: Support library includes// - - -//TODO: Lumiera header includes// -#include "include/nobugcfg.h" -#include "lumiera/lumiera.h" -#include "lumiera/config_interface.h" - -//TODO: internal/static forward declarations// - - -//TODO: System includes// - -/** - * @file - * - */ - - - -//code goes here// - - - -/** - * Shutdown procedure - * This shuts all subsystem which got initialized in lumiera_init down. - * Shutdowns should be arranged in reverse initialization order. - */ -void -lumiera_shutdown (void) -{ - TRACE (lumiera, "shutdown"); - - lumiera_config_interface_destroy (); -} - - - - - -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/src/lumiera/main.cpp b/src/lumiera/main.cpp index abd245442..f3450fa2b 100644 --- a/src/lumiera/main.cpp +++ b/src/lumiera/main.cpp @@ -80,10 +80,10 @@ main (int argc, const char* argv[]) catch (lumiera::Error& problem) { - application.abort (problem); + return application.abort (problem); } catch (...) { - application.abort(); + return application.abort(); } } diff --git a/src/lumiera/subsystemrunner.hpp b/src/lumiera/subsystemrunner.hpp index 48032c83a..9c57b241e 100644 --- a/src/lumiera/subsystemrunner.hpp +++ b/src/lumiera/subsystemrunner.hpp @@ -127,6 +127,8 @@ namespace lumiera { triggerStartup (Subsys* susy) { ASSERT (susy); + INFO (operate, "Starting subsystem \"%s\"", cStr(*susy)); + for_each (susy->prereq_, start_); bool started = susy.start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1));