WIP draft remainder of the global start/stop sequence, incl errorhandling

This commit is contained in:
Fischlurch 2008-12-03 07:43:45 +01:00 committed by Christian Thaeter
parent 01876fd576
commit 75b97ff9dd
8 changed files with 120 additions and 227 deletions

View file

@ -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

View file

@ -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

View file

@ -68,7 +68,7 @@ namespace lumiera {
private:
AppState ();
~AppState (); ///< deletion prohibited
~AppState ();
friend void boost::checked_delete<AppState>(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<SubsystemRunner> PSub;
PLife lifecycleHooks_;
PSub parts_;
PSub subsystems_;
bool emergency_;
friend class LifecycleHook;

View file

@ -1,66 +0,0 @@
/*
lumiera.c - Lumiera main application shell
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
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 <stdio.h>
/**
* @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:
*/

View file

@ -1,57 +0,0 @@
/*
lumiera.h - Lumiera main application shell
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
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 <nobug.h>
/**
* @file
*
*/
//TODO: declarations go here//
void
lumiera_shutdown (void);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -1,69 +0,0 @@
/*
lumiera_init.c - Lumiera initialization and shutdowen and global state
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
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:
*/

View file

@ -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();
}
}

View file

@ -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));