define logic for running several dependent subsystems in parallel
This commit is contained in:
parent
cc871fcaec
commit
b6a3139b66
2 changed files with 172 additions and 3 deletions
|
|
@ -25,6 +25,7 @@
|
|||
#include "include/lifecycle.h"
|
||||
#include "lumiera/appstate.hpp"
|
||||
#include "lib/lifecycleregistry.hpp"
|
||||
#include "lumiera/subsystemrunner.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "lumiera/config_interface.h"
|
||||
|
|
@ -34,12 +35,11 @@ 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::isnil;
|
||||
using util::cStr;
|
||||
//using util::isnil;
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
|
|
|
|||
169
src/lumiera/subsystemrunner.hpp
Normal file
169
src/lumiera/subsystemrunner.hpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
SUBSYSTEMRUNNER.hpp - helper for controlling execution of several dependant subsystems
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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_SUBSYSTEMRUNNER_H
|
||||
#define LUMIERA_SUBSYSTEMRUNNER_H
|
||||
|
||||
#include "include/error.hpp"
|
||||
#include "common/util.hpp"
|
||||
#include "lumiera/subsys.hpp"
|
||||
#include "common/multithread.hpp"
|
||||
|
||||
#include <boost/tr1/functional.hpp>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
using std::tr1::bind;
|
||||
using std::tr1::function;
|
||||
using std::vector;
|
||||
using util::cStr;
|
||||
using util::isnil;
|
||||
using util::and_all;
|
||||
using util::for_each;
|
||||
using util::removeall;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Implementation helper for managing execution of a collection of subsystems,
|
||||
* which may depend on one another and execute in parallel. Properties of the
|
||||
* subsystems are available through Subsys object refs, which act as handle.
|
||||
* In this context, "Subsystem" is an \em abstraction and doesn't necessarily
|
||||
* correspond to a single component, interface or plugin. It may well be a
|
||||
* complete layer of the application (e.g. the GUI).
|
||||
*
|
||||
* \par Protocol of operation
|
||||
* The SubsystemRunner is to be configured with a lumiera::Option object first.
|
||||
* Then, primary subsystems are \link #maybeRun provided \endlink for eventual
|
||||
* startup, which may depend on conditions defined by the subsystem. When
|
||||
* a component is actually to be pulled up, all of its prerequisite subsystems
|
||||
* shall be started in advance. Problems while starting may result in throwing
|
||||
* an exception, which is \em not handled here and aborts the whole operation.
|
||||
* On startup, a signal slot is reserved for each subsystem to notify the
|
||||
* SubsystemRunner on termination. It is the liability of the subsystems to
|
||||
* ensure this signal is activated regardless of what actually causes the
|
||||
* termination; failure to do so may deadlock the SubsystemRunner.
|
||||
*
|
||||
* Usually, the startup process is conducted from one (main) thread, which enters
|
||||
* a blocking wait() after starting the subsystems. Awakened by some termination
|
||||
* signal from one of the subsystems, termination of any remaining subsystems
|
||||
* will be triggered. The wait() function returns after shutdown of all subsystems,
|
||||
* signalling an emergency exit (caused by an exception) with its return value.
|
||||
*
|
||||
* @todo implement an object monitor primitive based on a mutex and a condition. Inherit from this privately and create local instances of the embedded Lock class to activate the locking and wait/notify
|
||||
* @todo maybe use my refArray (see builder) to use Subsys& instead of Subsys* ??
|
||||
*
|
||||
* @see lumiera::AppState
|
||||
* @see lumiera::Subsys
|
||||
* @see main.cpp
|
||||
*/
|
||||
class SubsystemRunner
|
||||
{
|
||||
Option& opts_;
|
||||
vector<Subsys*> running_;
|
||||
|
||||
function<void(Subsys&)> start_,
|
||||
killIt_;
|
||||
|
||||
public:
|
||||
|
||||
SubsystemRunner (Option& opts)
|
||||
: opts_(opts)
|
||||
, start_(bind (&SubsystemRunner::triggerStartup, this,_1))
|
||||
, killIt_(bind (&Subsys::triggerShutdown, _1))
|
||||
{ }
|
||||
|
||||
void
|
||||
maybeRun (Subsys& susy)
|
||||
{
|
||||
//Lock guard (*this);
|
||||
|
||||
if (!susy.isRunning() && susy.shouldStart (opts_))
|
||||
triggerStartup (&susy);
|
||||
if (susy.isRunning())
|
||||
running_.push_back (&susy);
|
||||
}
|
||||
|
||||
void
|
||||
shutdownAll ()
|
||||
{
|
||||
//Lock guard (*this);
|
||||
for_each (running_, killIt_);
|
||||
}
|
||||
|
||||
void
|
||||
wait ()
|
||||
{
|
||||
//Lock(*this).wait (&SubsystemRunner::allDead);
|
||||
return isEmergencyExit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void
|
||||
triggerStartup (Subsys* susy)
|
||||
{
|
||||
ASSERT (susy);
|
||||
for_each (susy->prereq_, start_);
|
||||
bool started = susy.start (opts_, bind (&SubsystemRunner::sigTerm, this, susy, _1));
|
||||
|
||||
if (started && !susy.isRunning())
|
||||
{
|
||||
throw error::Logic("Subsystem "+susy+" failed to start");
|
||||
}
|
||||
if (!and_all (susy->prereq_, isRunning_))
|
||||
{
|
||||
susy->triggerShutdown();
|
||||
throw error::Logic("Unable to start all prerequisites of Subsystem "+susy);
|
||||
} }
|
||||
|
||||
void
|
||||
sigTerm (Subsys* susy, Error* problem) ///< called from subsystem on termination
|
||||
{
|
||||
ASSERT (susy);
|
||||
//Lock guard (*this);
|
||||
ERROR_IF (susy.isRunning(), lumiera, "Subsystem '%s' signals termination, "
|
||||
"without resetting running state", cStr(susy));
|
||||
removeall (running_, susy);
|
||||
shutdownAll();
|
||||
//guard.notify();
|
||||
}
|
||||
|
||||
bool
|
||||
allDead ()
|
||||
{
|
||||
if (isEmergencyExit())
|
||||
; //Lock(*this).setTimeout(EMERGENCYTIMEOUT);
|
||||
|
||||
return isnil (running_); // end wait if no running subsystem left
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
#endif
|
||||
Loading…
Reference in a new issue