Commit 8e016a1e authored by Remi Mommsen's avatar Remi Mommsen Committed by Remi Mommsen
Browse files

references #144: use semaphore to prevent concurrent use of EVM/RUs or BUs on the same host

parent 7dfeb67a
#ifndef _evb_StateMachine_h_
#define _evb_StateMachine_h_
#include <boost/interprocess/sync/named_semaphore.hpp>
#include <boost/statechart/event_base.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/state_machine.hpp>
......@@ -35,6 +36,7 @@ namespace evb {
// Internal transition events //
////////////////////////////////
class StartConfigure: public boost::statechart::event<StartConfigure> {};
class ConfigureDone: public boost::statechart::event<ConfigureDone> {};
class DrainingDone: public boost::statechart::event<DrainingDone> {};
class ClearingDone: public boost::statechart::event<ClearingDone> {};
......@@ -89,6 +91,9 @@ namespace evb {
using SoapFsmEvents = std::list<std::string>;
SoapFsmEvents getSoapFsmEvents() const { return soapFsmEvents_; }
void acquireLock(const std::string& name);
void releaseLock(const std::string& name);
protected:
virtual void do_processSoapEvent(const std::string& event, std::string& newStateName);
......@@ -106,6 +111,7 @@ namespace evb {
xdata::UnsignedInteger32 runNumber_;
std::string stateName_;
volatile bool haveLock_;
xdata::UnsignedInteger32 monitoringRunNumber_;
xdata::String monitoringStateName_;
......@@ -222,7 +228,8 @@ evb::EvBStateMachine<MostDerived,InitialState>::EvBStateMachine
app->getApplicationContext()
),
runNumber_(0),
stateName_("uninitialized")
stateName_("uninitialized"),
haveLock_(false)
{
xdata::InfoSpace *is = app->getApplicationInfoSpace();
is->fireItemAvailable("rcmsStateListener",
......@@ -339,6 +346,43 @@ void evb::EvBStateMachine<MostDerived,InitialState>::updateMonitoringItems()
}
template <class MostDerived,class InitialState>
void evb::EvBStateMachine<MostDerived,InitialState>::acquireLock(const std::string& name)
{
boost::interprocess::named_semaphore semaphore(boost::interprocess::open_or_create,name.c_str(),1);
if ( haveLock_ || semaphore.try_wait() )
{
haveLock_ = true;
}
else
{
std::string msg = "Another ";
if (name == "evb::readoutunit")
msg += "RU or EVM";
else if (name == "evb::bu")
msg += "BU";
else
msg += "EvB application";
msg += " is already in Configured or Enabled state on this machine. Please destroy or Halt the other instance first.";
XCEPT_DECLARE(exception::FSM, sentinelException,msg);
this->post_event( Fail(sentinelException) );
}
}
template <class MostDerived,class InitialState>
void evb::EvBStateMachine<MostDerived,InitialState>::releaseLock(const std::string& name)
{
if ( haveLock_ )
{
boost::interprocess::named_semaphore semaphore(boost::interprocess::open_only,name.c_str());
semaphore.post();
}
haveLock_ = false;
}
template <class MostDerived,class InitialState>
void evb::EvBStateMachine<MostDerived,InitialState>::notifyRCMS
(
......
......@@ -55,6 +55,7 @@ namespace evb {
xdata::Double metaDataLowWaterMark;
xdata::UnsignedInteger32 checkCRC; // Check the CRC of the FED fragments for every Nth event
xdata::Boolean calculateCRC32c; // If set to true, a CRC32c checksum of data blob of each event is calculated
xdata::Boolean useLock; // Prevent more than one BU in Configured or Enabled state
xdata::Boolean deleteRawDataFiles; // If true, delete raw data files when the high-water mark is reached
xdata::Boolean ignoreResourceSummary; // If true, ignore the resource_summary file from hltd
xdata::Boolean closeOldRuns; // If true, create empty EoR files in any old run directories without EoR files
......@@ -106,6 +107,7 @@ namespace evb {
metaDataLowWaterMark(0.75),
checkCRC(1),
calculateCRC32c(true),
useLock(true),
deleteRawDataFiles(false),
ignoreResourceSummary(false),
closeOldRuns(true),
......@@ -164,6 +166,7 @@ namespace evb {
params.add("metaDataLowWaterMark", &metaDataLowWaterMark);
params.add("checkCRC", &checkCRC);
params.add("calculateCRC32c", &calculateCRC32c);
params.add("useLock", &useLock);
params.add("deleteRawDataFiles", &deleteRawDataFiles);
params.add("ignoreResourceSummary", &ignoreResourceSummary);
params.add("closeOldRuns", &closeOldRuns);
......
......@@ -35,6 +35,7 @@ namespace evb {
class Halted;
class Active;
// Inner states of Active
class PreConfigure;
class Configuring;
class Ready;
class Running;
......@@ -89,7 +90,9 @@ namespace evb {
using reactions = boost::mpl::list<
boost::statechart::transition<Halt,Halted>,
boost::statechart::in_state_reaction<Fail>
boost::statechart::in_state_reaction<Fail>,
boost::statechart::in_state_reaction<ConfigureDone>,
boost::statechart::in_state_reaction<DrainingDone>
>;
Failed(my_context c) : my_state("Failed", c)
......@@ -146,7 +149,7 @@ namespace evb {
/**
* The Active state of outer-state AllOk.
*/
class Active: public EvBState<Active,AllOk,Configuring>
class Active: public EvBState<Active,AllOk,PreConfigure>
{
public:
......@@ -167,7 +170,27 @@ namespace evb {
/**
* The Configuring state. Initial state of outer-state Active.
* The PreConfigure state. Initial state of outer-state Active.
*/
class PreConfigure: public EvBState<PreConfigure,Active>
{
public:
using reactions = boost::mpl::list<
boost::statechart::transition<StartConfigure,Configuring>
>;
PreConfigure(my_context c) : my_state("PreConfigure", c)
{ safeEntryAction(); }
virtual ~PreConfigure()
{ safeExitAction(); }
};
/**
* The Configuring state of outer-state Active.
*/
class Configuring: public EvBState<Configuring,Active>
{
......
......@@ -79,6 +79,7 @@ namespace evb {
xdata::UnsignedInteger32 fragmentRequestFIFOCapacity; // Capacity of the FIFO to store incoming fragment requests
xdata::UnsignedInteger32 checkCRC; // Check the CRC of the FED fragments for every Nth event
xdata::UnsignedInteger32 writeNextFragmentsToFile; // Write the next N fragments to text files
xdata::Boolean useLock; // Prevent more than one readoutunit in Configured or Enabled state
xdata::Boolean dropAtSocket; // If set to true, data is discarded after reading from the socket
xdata::Boolean dropAtStream; // If set to true, data is discarded after handing it to the FEROL stream
xdata::Boolean dropInputData; // If set to true, the input data is dropped
......@@ -114,6 +115,7 @@ namespace evb {
fragmentRequestFIFOCapacity(2048),
checkCRC(1),
writeNextFragmentsToFile(0),
useLock(true),
dropAtSocket(false),
dropAtStream(false),
dropInputData(false),
......@@ -152,6 +154,7 @@ namespace evb {
params.add("fragmentRequestFIFOCapacity", &fragmentRequestFIFOCapacity);
params.add("checkCRC", &checkCRC);
params.add("writeNextFragmentsToFile", &writeNextFragmentsToFile, InfoSpaceItems::change);
params.add("useLock", &useLock);
params.add("dropAtSocket", &dropAtSocket);
params.add("dropAtStream", &dropAtStream);
params.add("dropInputData", &dropInputData);
......
......@@ -111,8 +111,8 @@ namespace evb {
template<class Owner>
evb::readoutunit::StateMachine<Owner>::StateMachine(Owner* owner) :
EvBStateMachine<StateMachine<Owner>,readoutunit::Outermost<Owner>>(owner),
owner_(owner)
EvBStateMachine<StateMachine<Owner>,readoutunit::Outermost<Owner>>(owner),
owner_(owner)
{}
......
......@@ -39,6 +39,7 @@ namespace evb {
template<class> class Halted;
template<class> class Active;
// Inner states of Active
template<class> class PreConfigure;
template<class> class Configuring;
template<class> class Ready;
template<class> class Running;
......@@ -91,7 +92,9 @@ namespace evb {
using my_state = EvBState<Failed<Owner>,Outermost<Owner>>;
using reactions = boost::mpl::list<
boost::statechart::transition<Halt,Halted<Owner>>,
boost::statechart::in_state_reaction<Fail>
boost::statechart::in_state_reaction<Fail>,
boost::statechart::in_state_reaction<ConfigureDone>,
boost::statechart::in_state_reaction<DrainingDone>
>;
Failed(typename my_state::boost_state::my_context c) : my_state("Failed", c)
......@@ -157,12 +160,12 @@ namespace evb {
* The Active state of outer-state AllOk.
*/
template<class Owner>
class Active: public EvBState<Active<Owner>,AllOk<Owner>,boost::mpl::list<Configuring<Owner>>>
class Active: public EvBState<Active<Owner>,AllOk<Owner>,boost::mpl::list<PreConfigure<Owner>>>
{
public:
using my_state = EvBState<Active<Owner>,AllOk<Owner>,boost::mpl::list<Configuring<Owner>>>;
using my_state = EvBState<Active<Owner>,AllOk<Owner>,boost::mpl::list<PreConfigure<Owner>>>;
using reactions = boost::mpl::list<
boost::statechart::transition<Halt,Halted<Owner>>
>;
......@@ -172,11 +175,36 @@ namespace evb {
virtual ~Active()
{ this->safeExitAction(); }
virtual void entryAction();
virtual void exitAction();
};
/**
* The PreConfigured state. Initial state of outer-state Active.
*/
template<class Owner>
class PreConfigure: public EvBState<PreConfigure<Owner>,Active<Owner>>
{
public:
using my_state = EvBState<PreConfigure<Owner>,Active<Owner>>;
using reactions = boost::mpl::list<
boost::statechart::transition<StartConfigure,Configuring<Owner>>
>;
PreConfigure(typename my_state::boost_state::my_context c) : my_state("PreConfigure", c)
{ this->safeEntryAction(); }
virtual ~PreConfigure()
{ this->safeExitAction(); }
};
/**
* The Configuring state. Initial state of outer-state Active.
* The Configuring state of outer-state Active.
*/
template<class Owner>
class Configuring: public EvBState<Configuring<Owner>,Active<Owner>>
......@@ -427,6 +455,26 @@ void evb::readoutunit::Halted<Owner>::entryAction()
}
template<class Owner>
void evb::readoutunit::Active<Owner>::entryAction()
{
typename my_state::outermost_context_type& stateMachine = this->outermost_context();
if ( stateMachine.getOwner()->getConfiguration()->useLock )
stateMachine.acquireLock("evb::readoutunit");
this->post_event( StartConfigure() );
}
template<class Owner>
void evb::readoutunit::Active<Owner>::exitAction()
{
typename my_state::outermost_context_type& stateMachine = this->outermost_context();
stateMachine.releaseLock("evb::readoutunit");
}
template<class Owner>
void evb::readoutunit::Configuring<Owner>::entryAction()
{
......
......@@ -90,7 +90,13 @@ void evb::bu::Ready::entryAction()
void evb::bu::Active::entryAction()
{
outermost_context_type& stateMachine = outermost_context();
if ( stateMachine.bu()->getConfiguration()->useLock )
stateMachine.acquireLock("evb::bu");
stateMachine.resourceManager()->requestEvents(true);
this->post_event( StartConfigure() );
}
......@@ -98,6 +104,8 @@ void evb::bu::Active::exitAction()
{
outermost_context_type& stateMachine = outermost_context();
stateMachine.resourceManager()->requestEvents(false);
stateMachine.releaseLock("evb::bu");
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment