2007-08-14 08:14:21 +02:00
/*
2008-11-30 06:43:51 +01:00
AppState - application initialisation and behaviour
2010-12-17 23:28:49 +01:00
2008-03-10 04:25:03 +01:00
Copyright ( C ) Lumiera . org
2008-04-14 05:15:16 +02:00
2008 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
2007-08-14 08:14:21 +02:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
2007-08-14 08:14:21 +02:00
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 .
2010-12-17 23:28:49 +01:00
2007-08-14 08:14:21 +02:00
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 0213 9 , USA .
2010-12-17 23:28:49 +01:00
2007-08-14 08:14:21 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-27 00:53:35 +01:00
# include "lib/error.hpp"
2008-11-30 07:56:00 +01:00
# include "include/lifecycle.h"
2008-12-18 08:12:40 +01:00
# include "common/appstate.hpp"
2008-12-31 05:05:34 +01:00
# include "common/subsystem-runner.hpp"
2008-11-30 06:43:51 +01:00
2008-12-02 04:53:30 +01:00
extern " C " {
2008-12-18 08:54:33 +01:00
# include "common/config_interface.h"
2008-12-02 04:53:30 +01:00
2008-12-18 08:54:33 +01:00
# include "common/interface.h"
# include "common/interfaceregistry.h"
# include "common/plugin.h"
2008-12-02 04:53:30 +01:00
}
2008-12-17 17:53:32 +01:00
# include "lib/util.hpp"
2008-12-02 07:49:24 +01:00
# include "include/configfacade.hpp" //////////TODO: temp hack to force configfacade.o to be linked in
2007-08-14 08:14:21 +02:00
2008-12-03 07:43:45 +01:00
using util : : cStr ;
2007-08-23 17:52:33 +02:00
2007-08-14 08:14:21 +02:00
2008-12-02 04:53:30 +01:00
2008-11-30 03:08:48 +01:00
namespace lumiera {
2007-08-14 08:14:21 +02:00
2008-12-03 07:43:45 +01:00
namespace { // implementation details
inline void
log_and_clear_unexpected_errorstate ( )
{
2009-10-02 17:26:50 +02:00
if ( lumiera_err errorstate = lumiera_error ( ) )
2009-01-24 03:13:08 +01:00
ALERT ( common , " *** Unexpected error: %s \n Triggering emergency exit. " , errorstate ) ;
2009-01-14 12:15:13 +01:00
}
void
createAppStateInstance ( ) {
AppState : : instance ( ) ;
}
LifecycleHook schedule_ ( ON_BASIC_INIT , & createAppStateInstance ) ;
}
2008-11-30 06:43:51 +01:00
2008-04-14 05:15:16 +02:00
2008-11-30 06:43:51 +01:00
2008-11-30 03:08:48 +01:00
/** perform initialisation triggered on first access.
2008-04-13 23:54:39 +02:00
* Will execute the ON_BASIC_INIT hook , but under typical
* circumstances this is a NOP , because when callbacks are
2008-11-30 06:43:51 +01:00
* added to this hook , the AppState singleton instance has
2008-04-13 23:54:39 +02:00
* already been created . For this reason , there is special
* treatment for the ON_BASIC_INIT in LifecycleHook : : add ,
2008-04-14 05:15:16 +02:00
* causing the provided callbacks to be fired immediately .
* ( btw , this is nothing to be worried of , because from
* client codes POV it just behaves like intended ) .
2007-08-14 08:14:21 +02:00
*/
2008-11-30 06:43:51 +01:00
AppState : : AppState ( )
2009-01-14 12:15:13 +01:00
: subsystems_ ( 0 )
2008-12-08 03:01:02 +01:00
, emergency_ ( false )
, core_up_ ( false )
2009-01-14 12:15:13 +01:00
{ }
2007-08-14 08:14:21 +02:00
2008-11-30 06:43:51 +01:00
AppState &
AppState : : instance ( ) // Meyer's singleton
{
static scoped_ptr < AppState > theApp_ ( 0 ) ;
if ( ! theApp_ ) theApp_ . reset ( new AppState ( ) ) ;
return * theApp_ ;
}
2007-08-23 17:52:33 +02:00
2008-12-02 04:53:30 +01:00
2008-12-03 07:43:45 +01:00
// ===== Implementation startup and shutdown sequence for main() ========
2008-12-02 04:53:30 +01:00
# define _THROW_IF \
if ( lumiera_error_peek ( ) ) \
2008-12-03 07:43:45 +01:00
throw error : : Fatal ( lumiera_error ( ) ) ;
2008-12-02 04:53:30 +01:00
2008-12-01 05:35:19 +01:00
void
2008-12-02 04:53:30 +01:00
AppState : : init ( Option & options )
2008-12-01 05:35:19 +01:00
{
2009-01-24 03:13:08 +01:00
TRACE ( common , " initialising application core... " ) ;
2008-12-02 04:53:30 +01:00
lumiera_interfaceregistry_init ( ) ;
_THROW_IF
TODO ( " use a plugindb instead of loading all plugins at once " ) ;
lumiera_plugin_discover ( lumiera_plugin_load , lumiera_plugin_register ) ;
_THROW_IF
lumiera_config_interface_init ( ) ;
_THROW_IF
2008-12-08 03:01:02 +01:00
core_up_ = true ;
2009-01-14 12:15:13 +01:00
LifecycleHook : : trigger ( ON_GLOBAL_INIT ) ;
2008-12-02 04:53:30 +01:00
_THROW_IF
2008-12-03 07:43:45 +01:00
subsystems_ . reset ( new SubsystemRunner ( options ) ) ;
2009-01-24 03:13:08 +01:00
TRACE ( common , " Lumiera core started successfully. " ) ;
2008-12-01 05:35:19 +01:00
}
void
2008-12-03 07:43:45 +01:00
AppState : : maybeStart ( lumiera : : Subsys & subsys )
2008-12-01 05:35:19 +01:00
{
2009-01-24 03:13:08 +01:00
TRACE ( common , " maybe startup %s...? " , cStr ( subsys ) ) ;
REQUIRE ( subsystems_ ) ;
2008-12-03 07:43:45 +01:00
subsystems_ - > maybeRun ( subsys ) ;
2008-12-01 05:35:19 +01:00
}
2008-12-01 08:04:43 +01:00
typedef AppState : : ExitCode ExitCode ;
2008-12-01 05:35:19 +01:00
2008-12-03 07:43:45 +01:00
/** @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 .
*/
2008-12-01 05:35:19 +01:00
ExitCode
AppState : : maybeWait ( )
{
2008-12-03 07:43:45 +01:00
if ( subsystems_ )
{
emergency_ | = subsystems_ - > wait ( ) ;
subsystems_ . reset ( 0 ) ;
}
2009-01-24 03:13:08 +01:00
NOTICE ( common , " Shutting down Lumiera... " ) ;
2008-12-03 07:43:45 +01:00
if ( emergency_ )
{
2009-01-24 03:13:08 +01:00
ALERT ( common , " Triggering emergency exit... " ) ;
2009-01-14 12:15:13 +01:00
LifecycleHook : : trigger ( ON_EMERGENCY ) ;
2008-12-03 07:43:45 +01:00
return CLEAN_EMERGENCY_EXIT ;
}
else
{
2009-01-14 12:15:13 +01:00
LifecycleHook : : trigger ( ON_GLOBAL_SHUTDOWN ) ;
2008-12-03 07:43:45 +01:00
return NORMAL_EXIT ;
}
2008-12-01 05:35:19 +01:00
}
ExitCode
AppState : : abort ( lumiera : : Error & problem )
{
2008-12-03 07:43:45 +01:00
2009-09-05 19:11:17 +02:00
INFO ( common , " Address of Config Facade = %p " , & lumiera : : Config : : instance ( ) ) ; //////////TODO: a temp hack to force configfacade.cpp to be linked into lumiera exe.
2008-12-03 07:43:45 +01:00
2009-01-24 03:13:08 +01:00
ERROR ( common , " Aborting Lumiera after unhandled error: %s " , cStr ( problem . what ( ) ) ) ;
2008-12-03 07:43:45 +01:00
log_and_clear_unexpected_errorstate ( ) ;
try
{
2008-12-04 04:21:02 +01:00
if ( subsystems_ )
{
subsystems_ - > triggerEmergency ( true ) ;
subsystems_ - > shutdownAll ( ) ;
}
2008-12-03 07:43:45 +01:00
return maybeWait ( ) ;
}
catch ( . . . )
{
return abort ( ) ;
}
2008-12-01 05:35:19 +01:00
}
ExitCode
2008-12-03 07:43:45 +01:00
AppState : : abort ( ) throw ( )
2008-12-01 05:35:19 +01:00
{
2008-12-03 07:43:45 +01:00
log_and_clear_unexpected_errorstate ( ) ;
if ( emergency_ )
{
2009-01-14 12:15:13 +01:00
LifecycleHook : : trigger ( ON_EMERGENCY ) ;
2008-12-03 07:43:45 +01:00
return FAILED_EMERGENCY_EXIT ;
}
else
{
2009-01-14 12:15:13 +01:00
LifecycleHook : : trigger ( ON_GLOBAL_SHUTDOWN ) ;
2008-12-03 07:43:45 +01:00
return CLEAN_EXIT_AFTER_ERROR ;
}
2008-12-01 05:35:19 +01:00
}
2008-12-03 07:43:45 +01:00
/** 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 ( )
{
2008-12-08 03:01:02 +01:00
if ( core_up_ )
try
{
2009-01-24 03:13:08 +01:00
TRACE ( common , " shutting down basic application layer... " ) ;
2008-12-08 03:01:02 +01:00
lumiera_config_interface_destroy ( ) ;
lumiera_interfaceregistry_destroy ( ) ;
}
2008-12-03 07:43:45 +01:00
catch ( . . . )
{
log_and_clear_unexpected_errorstate ( ) ;
} }
2008-12-01 05:35:19 +01:00
2008-11-30 06:43:51 +01:00
2008-03-10 06:09:44 +01:00
} // namespace lumiera