mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 08:41:16 +00:00
Extract state queue into own class. Use in device, plugins
This commit is contained in:
parent
4487b81de8
commit
f515eb1100
|
@ -92,6 +92,7 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
|
||||||
set(FSM_PUBLIC_HEADER_FILES
|
set(FSM_PUBLIC_HEADER_FILES
|
||||||
StateMachine.h
|
StateMachine.h
|
||||||
States.h
|
States.h
|
||||||
|
StateQueue.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(FSM_SOURCE_FILES
|
set(FSM_SOURCE_FILES
|
||||||
|
|
|
@ -66,6 +66,27 @@ constexpr uint64_t FairMQDevice::DefaultMaxRunTime;
|
||||||
constexpr float FairMQDevice::DefaultRate;
|
constexpr float FairMQDevice::DefaultRate;
|
||||||
constexpr const char* FairMQDevice::DefaultSession;
|
constexpr const char* FairMQDevice::DefaultSession;
|
||||||
|
|
||||||
|
struct StateSubscription
|
||||||
|
{
|
||||||
|
fair::mq::StateMachine& fStateMachine;
|
||||||
|
fair::mq::StateQueue& fStateQueue;
|
||||||
|
string fId;
|
||||||
|
|
||||||
|
explicit StateSubscription(const string& id, fair::mq::StateMachine& stateMachine, fair::mq::StateQueue& stateQueue)
|
||||||
|
: fStateMachine(stateMachine)
|
||||||
|
, fStateQueue(stateQueue)
|
||||||
|
, fId(id)
|
||||||
|
{
|
||||||
|
fStateMachine.SubscribeToStateChange(fId, [&](fair::mq::State state) {
|
||||||
|
fStateQueue.Push(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
~StateSubscription() {
|
||||||
|
fStateMachine.UnsubscribeFromStateChange(fId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
FairMQDevice::FairMQDevice()
|
FairMQDevice::FairMQDevice()
|
||||||
: FairMQDevice(nullptr, {0, 0, 0})
|
: FairMQDevice(nullptr, {0, 0, 0})
|
||||||
{}
|
{}
|
||||||
|
@ -106,9 +127,6 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
|
||||||
, fMaxRunRuntimeInS(DefaultMaxRunTime)
|
, fMaxRunRuntimeInS(DefaultMaxRunTime)
|
||||||
, fInitializationTimeoutInS(DefaultInitTimeout)
|
, fInitializationTimeoutInS(DefaultInitTimeout)
|
||||||
, fRawCmdLineArgs()
|
, fRawCmdLineArgs()
|
||||||
, fStates()
|
|
||||||
, fStatesMtx()
|
|
||||||
, fStatesCV()
|
|
||||||
, fTransitionMtx()
|
, fTransitionMtx()
|
||||||
, fTransitioning(false)
|
, fTransitioning(false)
|
||||||
{
|
{
|
||||||
|
@ -127,11 +145,7 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
|
||||||
fStateMachine.HandleStates([&](fair::mq::State state) {
|
fStateMachine.HandleStates([&](fair::mq::State state) {
|
||||||
LOG(trace) << "device notified on new state: " << state;
|
LOG(trace) << "device notified on new state: " << state;
|
||||||
|
|
||||||
{
|
fStateQueue.Push(state);
|
||||||
lock_guard<mutex> lock(fStatesMtx);
|
|
||||||
fStates.push(state);
|
|
||||||
}
|
|
||||||
fStatesCV.notify_all();
|
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case fair::mq::State::InitializingDevice:
|
case fair::mq::State::InitializingDevice:
|
||||||
|
@ -167,29 +181,6 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
|
||||||
fStateMachine.Start();
|
fStateMachine.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
fair::mq::State FairMQDevice::WaitForNextState()
|
|
||||||
{
|
|
||||||
unique_lock<mutex> lock(fStatesMtx);
|
|
||||||
while (fStates.empty()) {
|
|
||||||
fStatesCV.wait_for(lock, chrono::milliseconds(50));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto state = fStates.front();
|
|
||||||
|
|
||||||
if (state == fair::mq::State::Error) {
|
|
||||||
throw DeviceStateError("Device transitioned to error state.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fStates.pop();
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQDevice::WaitForState(fair::mq::State state)
|
|
||||||
{
|
|
||||||
while (WaitForNextState() != state) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQDevice::TransitionTo(const fair::mq::State s)
|
void FairMQDevice::TransitionTo(const fair::mq::State s)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
@ -202,6 +193,10 @@ void FairMQDevice::TransitionTo(const fair::mq::State s)
|
||||||
}
|
}
|
||||||
|
|
||||||
using fair::mq::State;
|
using fair::mq::State;
|
||||||
|
|
||||||
|
StateQueue sq;
|
||||||
|
StateSubscription ss(tools::ToString(fId, ".TransitionTo"), fStateMachine, sq);
|
||||||
|
|
||||||
State currentState = GetCurrentState();
|
State currentState = GetCurrentState();
|
||||||
|
|
||||||
while (s != currentState) {
|
while (s != currentState) {
|
||||||
|
@ -244,7 +239,7 @@ void FairMQDevice::TransitionTo(const fair::mq::State s)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentState = WaitForNextState();
|
currentState = sq.WaitForNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <StateMachine.h>
|
#include <StateMachine.h>
|
||||||
#include <FairMQTransportFactory.h>
|
#include <FairMQTransportFactory.h>
|
||||||
#include <fairmq/Transports.h>
|
#include <fairmq/Transports.h>
|
||||||
|
#include <fairmq/StateQueue.h>
|
||||||
|
|
||||||
#include <FairMQSocket.h>
|
#include <FairMQSocket.h>
|
||||||
#include <FairMQChannel.h>
|
#include <FairMQChannel.h>
|
||||||
|
@ -498,8 +499,8 @@ class FairMQDevice
|
||||||
void WaitForEndOfState(const fair::mq::Transition transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState).")));
|
void WaitForEndOfState(const fair::mq::Transition transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState).")));
|
||||||
void WaitForEndOfState(const std::string& transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState)."))) { WaitForState(transition); }
|
void WaitForEndOfState(const std::string& transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState)."))) { WaitForState(transition); }
|
||||||
|
|
||||||
fair::mq::State WaitForNextState();
|
fair::mq::State WaitForNextState() { return fStateQueue.WaitForNext(); }
|
||||||
void WaitForState(fair::mq::State state);
|
void WaitForState(fair::mq::State state) { fStateQueue.WaitForState(state); }
|
||||||
void WaitForState(const std::string& state) { WaitForState(fair::mq::GetState(state)); }
|
void WaitForState(const std::string& state) { WaitForState(fair::mq::GetState(state)); }
|
||||||
|
|
||||||
void TransitionTo(const fair::mq::State state);
|
void TransitionTo(const fair::mq::State state);
|
||||||
|
@ -522,8 +523,6 @@ class FairMQDevice
|
||||||
static std::string GetStateName(const fair::mq::State state) { return fair::mq::GetStateName(state); }
|
static std::string GetStateName(const fair::mq::State state) { return fair::mq::GetStateName(state); }
|
||||||
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::GetTransitionName(transition); }
|
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::GetTransitionName(transition); }
|
||||||
|
|
||||||
struct DeviceStateError : std::runtime_error { using std::runtime_error::runtime_error; };
|
|
||||||
|
|
||||||
static constexpr const char* DefaultId = "";
|
static constexpr const char* DefaultId = "";
|
||||||
static constexpr int DefaultIOThreads = 1;
|
static constexpr int DefaultIOThreads = 1;
|
||||||
static constexpr const char* DefaultTransportName = "zeromq";
|
static constexpr const char* DefaultTransportName = "zeromq";
|
||||||
|
@ -589,9 +588,7 @@ class FairMQDevice
|
||||||
int fInitializationTimeoutInS;
|
int fInitializationTimeoutInS;
|
||||||
std::vector<std::string> fRawCmdLineArgs;
|
std::vector<std::string> fRawCmdLineArgs;
|
||||||
|
|
||||||
std::queue<fair::mq::State> fStates;
|
fair::mq::StateQueue fStateQueue;
|
||||||
std::mutex fStatesMtx;
|
|
||||||
std::condition_variable fStatesCV;
|
|
||||||
|
|
||||||
std::mutex fTransitionMtx;
|
std::mutex fTransitionMtx;
|
||||||
bool fTransitioning;
|
bool fTransitioning;
|
||||||
|
|
94
fairmq/StateQueue.h
Normal file
94
fairmq/StateQueue.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
|
* *
|
||||||
|
* This software is distributed under the terms of the *
|
||||||
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef FAIRMQSTATEQUEUE_H_
|
||||||
|
#define FAIRMQSTATEQUEUE_H_
|
||||||
|
|
||||||
|
#include <fairmq/States.h>
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
#include <utility> // pair
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace fair
|
||||||
|
{
|
||||||
|
namespace mq
|
||||||
|
{
|
||||||
|
|
||||||
|
class StateQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StateQueue() {}
|
||||||
|
~StateQueue() {}
|
||||||
|
|
||||||
|
fair::mq::State WaitForNext()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(fMtx);
|
||||||
|
while (fStates.empty()) {
|
||||||
|
fCV.wait_for(lock, std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
fair::mq::State state = fStates.front();
|
||||||
|
|
||||||
|
if (state == fair::mq::State::Error) {
|
||||||
|
throw DeviceErrorState("Controlled device transitioned to error state.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fStates.pop();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Rep, typename Period>
|
||||||
|
std::pair<bool, fair::mq::State> WaitForNext(std::chrono::duration<Rep, Period> const& duration)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(fMtx);
|
||||||
|
fCV.wait_for(lock, duration);
|
||||||
|
|
||||||
|
if (fStates.empty()) {
|
||||||
|
return { false, fair::mq::State::Ok };
|
||||||
|
}
|
||||||
|
|
||||||
|
fair::mq::State state = fStates.front();
|
||||||
|
|
||||||
|
if (state == fair::mq::State::Error) {
|
||||||
|
throw DeviceErrorState("Controlled device transitioned to error state.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fStates.pop();
|
||||||
|
return { true, state };
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitForState(fair::mq::State state) { while (WaitForNext() != state) {} }
|
||||||
|
|
||||||
|
void Push(fair::mq::State state)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(fMtx);
|
||||||
|
fStates.push(state);
|
||||||
|
}
|
||||||
|
fCV.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(fMtx);
|
||||||
|
fStates = std::queue<fair::mq::State>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::queue<fair::mq::State> fStates;
|
||||||
|
std::mutex fMtx;
|
||||||
|
std::condition_variable fCV;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mq
|
||||||
|
} // namespace fair
|
||||||
|
|
||||||
|
#endif /* FAIRMQSTATEQUEUE_H_ */
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace fair
|
namespace fair
|
||||||
{
|
{
|
||||||
|
@ -57,6 +58,8 @@ std::string GetTransitionName(const Transition);
|
||||||
State GetState(const std::string& state);
|
State GetState(const std::string& state);
|
||||||
Transition GetTransition(const std::string& transition);
|
Transition GetTransition(const std::string& transition);
|
||||||
|
|
||||||
|
struct DeviceErrorState : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||||
|
|
||||||
inline std::ostream& operator<<(std::ostream& os, const State& state) { return os << GetStateName(state); }
|
inline std::ostream& operator<<(std::ostream& os, const State& state) { return os << GetStateName(state); }
|
||||||
inline std::ostream& operator<<(std::ostream& os, const Transition& transition) { return os << GetTransitionName(transition); }
|
inline std::ostream& operator<<(std::ostream& os, const Transition& transition) { return os << GetTransitionName(transition); }
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,7 @@ Control::Control(const string& name, const Plugin::Version version, const string
|
||||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||||
, fControllerThread()
|
, fControllerThread()
|
||||||
, fSignalHandlerThread()
|
, fSignalHandlerThread()
|
||||||
, fEvents()
|
|
||||||
, fEventsMutex()
|
|
||||||
, fControllerMutex()
|
, fControllerMutex()
|
||||||
, fNewEvent()
|
|
||||||
, fDeviceShutdownRequested(false)
|
, fDeviceShutdownRequested(false)
|
||||||
, fDeviceHasShutdown(false)
|
, fDeviceHasShutdown(false)
|
||||||
, fPluginShutdownRequested(false)
|
, fPluginShutdownRequested(false)
|
||||||
|
@ -57,16 +54,11 @@ Control::Control(const string& name, const Plugin::Version version, const string
|
||||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||||
LOG(trace) << "control plugin notified on new state: " << newState;
|
LOG(trace) << "control plugin notified on new state: " << newState;
|
||||||
|
|
||||||
{
|
fStateQueue.Push(newState);
|
||||||
lock_guard<mutex> lock{fEventsMutex};
|
|
||||||
fEvents.push(newState);
|
|
||||||
}
|
|
||||||
fNewEvent.notify_one();
|
|
||||||
|
|
||||||
if (newState == DeviceState::Error) {
|
if (newState == DeviceState::Error) {
|
||||||
fPluginShutdownRequested = true;
|
fPluginShutdownRequested = true;
|
||||||
fDeviceShutdownRequested = true;
|
fDeviceShutdownRequested = true;
|
||||||
// throw DeviceErrorState("Controlled device transitioned to error state.");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -103,36 +95,17 @@ Control::Control(const string& name, const Plugin::Version version, const string
|
||||||
auto Control::RunStartupSequence() -> void
|
auto Control::RunStartupSequence() -> void
|
||||||
{
|
{
|
||||||
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
||||||
while (WaitForNextState() != DeviceState::InitializingDevice) {}
|
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
||||||
while (WaitForNextState() != DeviceState::Initialized) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Initialized) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::Bind);
|
ChangeDeviceState(DeviceStateTransition::Bind);
|
||||||
while (WaitForNextState() != DeviceState::Bound) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Bound) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::Connect);
|
ChangeDeviceState(DeviceStateTransition::Connect);
|
||||||
while (WaitForNextState() != DeviceState::DeviceReady) {}
|
while (fStateQueue.WaitForNext() != DeviceState::DeviceReady) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::InitTask);
|
ChangeDeviceState(DeviceStateTransition::InitTask);
|
||||||
while (WaitForNextState() != DeviceState::Ready) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Ready) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::Run);
|
ChangeDeviceState(DeviceStateTransition::Run);
|
||||||
while (WaitForNextState() != DeviceState::Running) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Running) {}
|
||||||
}
|
|
||||||
|
|
||||||
auto Control::WaitForNextState() -> DeviceState
|
|
||||||
{
|
|
||||||
unique_lock<mutex> lock{fEventsMutex};
|
|
||||||
while (fEvents.empty()) {
|
|
||||||
fNewEvent.wait_for(lock, chrono::milliseconds(50));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = fEvents.front();
|
|
||||||
|
|
||||||
if (result == DeviceState::Error) {
|
|
||||||
ReleaseDeviceControl();
|
|
||||||
throw DeviceErrorState("Controlled device transitioned to error state.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fEvents.pop();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ControlPluginProgramOptions() -> Plugin::ProgOptions
|
auto ControlPluginProgramOptions() -> Plugin::ProgOptions
|
||||||
|
@ -204,7 +177,7 @@ try {
|
||||||
case 'i':
|
case 'i':
|
||||||
cout << "\n --> [i] init device\n\n" << flush;
|
cout << "\n --> [i] init device\n\n" << flush;
|
||||||
if (ChangeDeviceState(DeviceStateTransition::InitDevice)) {
|
if (ChangeDeviceState(DeviceStateTransition::InitDevice)) {
|
||||||
while (WaitForNextState() != DeviceState::InitializingDevice) {}
|
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -274,7 +247,6 @@ try {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetCurrentDeviceState() == DeviceState::Error) {
|
if (GetCurrentDeviceState() == DeviceState::Error) {
|
||||||
ReleaseDeviceControl();
|
|
||||||
throw DeviceErrorState("Controlled device transitioned to error state.");
|
throw DeviceErrorState("Controlled device transitioned to error state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +260,7 @@ try {
|
||||||
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
||||||
LOG(debug) << e.what();
|
LOG(debug) << e.what();
|
||||||
} catch (DeviceErrorState&) {
|
} catch (DeviceErrorState&) {
|
||||||
|
ReleaseDeviceControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Control::PrintInteractiveHelpColor() -> void
|
auto Control::PrintInteractiveHelpColor() -> void
|
||||||
|
@ -397,15 +370,10 @@ try {
|
||||||
{
|
{
|
||||||
// Wait for next state, which is DeviceState::Ready,
|
// Wait for next state, which is DeviceState::Ready,
|
||||||
// or for device shutdown request (Ctrl-C)
|
// or for device shutdown request (Ctrl-C)
|
||||||
unique_lock<mutex> lock{fEventsMutex};
|
pair<bool, fair::mq::State> result;
|
||||||
while (fEvents.empty() && !fDeviceShutdownRequested) {
|
do {
|
||||||
fNewEvent.wait_for(lock, chrono::milliseconds(50));
|
result = fStateQueue.WaitForNext(chrono::milliseconds(50));
|
||||||
}
|
} while (result.first == false && !fDeviceShutdownRequested);
|
||||||
|
|
||||||
if (fEvents.front() == DeviceState::Error) {
|
|
||||||
ReleaseDeviceControl();
|
|
||||||
throw DeviceErrorState("Controlled device transitioned to error state.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RunShutdownSequence();
|
RunShutdownSequence();
|
||||||
|
@ -413,6 +381,7 @@ try {
|
||||||
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
||||||
LOG(debug) << e.what();
|
LOG(debug) << e.what();
|
||||||
} catch (DeviceErrorState&) {
|
} catch (DeviceErrorState&) {
|
||||||
|
ReleaseDeviceControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Control::SignalHandler() -> void
|
auto Control::SignalHandler() -> void
|
||||||
|
@ -440,6 +409,7 @@ auto Control::SignalHandler() -> void
|
||||||
} catch (PluginServices::DeviceControlError& e) {
|
} catch (PluginServices::DeviceControlError& e) {
|
||||||
LOG(info) << "Graceful device shutdown failed: " << e.what() << " If hanging, hit Ctrl-C again to abort immediately.";
|
LOG(info) << "Graceful device shutdown failed: " << e.what() << " If hanging, hit Ctrl-C again to abort immediately.";
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
ReleaseDeviceControl();
|
||||||
LOG(info) << "Graceful device shutdown failed. If hanging, hit Ctrl-C again to abort immediately.";
|
LOG(info) << "Graceful device shutdown failed. If hanging, hit Ctrl-C again to abort immediately.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,7 +420,7 @@ auto Control::RunShutdownSequence() -> void
|
||||||
{
|
{
|
||||||
auto nextState = GetCurrentDeviceState();
|
auto nextState = GetCurrentDeviceState();
|
||||||
if (nextState != DeviceState::Error) {
|
if (nextState != DeviceState::Error) {
|
||||||
EmptyEventQueue();
|
fStateQueue.Clear();
|
||||||
}
|
}
|
||||||
while (nextState != DeviceState::Exiting && nextState != DeviceState::Error) {
|
while (nextState != DeviceState::Exiting && nextState != DeviceState::Error) {
|
||||||
switch (nextState) {
|
switch (nextState) {
|
||||||
|
@ -473,19 +443,13 @@ auto Control::RunShutdownSequence() -> void
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextState = WaitForNextState();
|
nextState = fStateQueue.WaitForNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
fDeviceHasShutdown = true;
|
fDeviceHasShutdown = true;
|
||||||
ReleaseDeviceControl();
|
ReleaseDeviceControl();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Control::EmptyEventQueue() -> void
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fEventsMutex};
|
|
||||||
fEvents = queue<DeviceState>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
Control::~Control()
|
Control::~Control()
|
||||||
{
|
{
|
||||||
// Notify threads to exit
|
// Notify threads to exit
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <fairmq/Plugin.h>
|
#include <fairmq/Plugin.h>
|
||||||
#include <fairmq/Version.h>
|
#include <fairmq/Version.h>
|
||||||
|
#include <fairmq/StateQueue.h>
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
@ -41,23 +42,17 @@ class Control : public Plugin
|
||||||
static auto PrintStateMachineColor() -> void;
|
static auto PrintStateMachineColor() -> void;
|
||||||
static auto PrintStateMachine() -> void;
|
static auto PrintStateMachine() -> void;
|
||||||
auto StaticMode() -> void;
|
auto StaticMode() -> void;
|
||||||
auto WaitForNextState() -> DeviceState;
|
|
||||||
auto SignalHandler() -> void;
|
auto SignalHandler() -> void;
|
||||||
auto RunShutdownSequence() -> void;
|
auto RunShutdownSequence() -> void;
|
||||||
auto RunStartupSequence() -> void;
|
auto RunStartupSequence() -> void;
|
||||||
auto EmptyEventQueue() -> void;
|
|
||||||
|
|
||||||
std::thread fControllerThread;
|
std::thread fControllerThread;
|
||||||
std::thread fSignalHandlerThread;
|
std::thread fSignalHandlerThread;
|
||||||
std::queue<DeviceState> fEvents;
|
|
||||||
std::mutex fEventsMutex;
|
|
||||||
std::mutex fControllerMutex;
|
std::mutex fControllerMutex;
|
||||||
std::condition_variable fNewEvent;
|
|
||||||
std::atomic<bool> fDeviceShutdownRequested;
|
std::atomic<bool> fDeviceShutdownRequested;
|
||||||
std::atomic<bool> fDeviceHasShutdown;
|
std::atomic<bool> fDeviceHasShutdown;
|
||||||
std::atomic<bool> fPluginShutdownRequested;
|
std::atomic<bool> fPluginShutdownRequested;
|
||||||
|
fair::mq::StateQueue fStateQueue;
|
||||||
struct DeviceErrorState : std::runtime_error { using std::runtime_error::runtime_error; };
|
|
||||||
}; /* class Control */
|
}; /* class Control */
|
||||||
|
|
||||||
auto ControlPluginProgramOptions() -> Plugin::ProgOptions;
|
auto ControlPluginProgramOptions() -> Plugin::ProgOptions;
|
||||||
|
|
|
@ -42,9 +42,6 @@ DDS::DDS(const string& name, const Plugin::Version version, const string& mainta
|
||||||
, fStopCondition()
|
, fStopCondition()
|
||||||
, fTransitions({ "BIND", "CONNECT", "INIT TASK", "RUN", "STOP", "RESET TASK", "RESET DEVICE" })
|
, fTransitions({ "BIND", "CONNECT", "INIT TASK", "RUN", "STOP", "RESET TASK", "RESET DEVICE" })
|
||||||
, fControllerThread()
|
, fControllerThread()
|
||||||
, fEvents()
|
|
||||||
, fEventsMutex()
|
|
||||||
, fNewEvent()
|
|
||||||
, fCurrentState(DeviceState::Idle)
|
, fCurrentState(DeviceState::Idle)
|
||||||
, fLastState(DeviceState::Idle)
|
, fLastState(DeviceState::Idle)
|
||||||
, fDeviceTerminationRequested(false)
|
, fDeviceTerminationRequested(false)
|
||||||
|
@ -86,11 +83,7 @@ auto DDS::HandleControl() -> void
|
||||||
|
|
||||||
// subscribe to device state changes, pushing new state changes into the event queue
|
// subscribe to device state changes, pushing new state changes into the event queue
|
||||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||||
{
|
fStateQueue.Push(newState);
|
||||||
lock_guard<mutex> lock{fEventsMutex};
|
|
||||||
fEvents.push(newState);
|
|
||||||
}
|
|
||||||
fNewEvent.notify_one();
|
|
||||||
if (newState == DeviceState::Exiting) {
|
if (newState == DeviceState::Exiting) {
|
||||||
fDeviceTerminationRequested = true;
|
fDeviceTerminationRequested = true;
|
||||||
}
|
}
|
||||||
|
@ -108,11 +101,11 @@ auto DDS::HandleControl() -> void
|
||||||
});
|
});
|
||||||
|
|
||||||
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
||||||
while (WaitForNextState() != DeviceState::InitializingDevice) {}
|
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
||||||
while (WaitForNextState() != DeviceState::Initialized) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Initialized) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::Bind);
|
ChangeDeviceState(DeviceStateTransition::Bind);
|
||||||
while (WaitForNextState() != DeviceState::Bound) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Bound) {}
|
||||||
|
|
||||||
// in the Initializing state subscribe to receive addresses of connecting channels from DDS
|
// in the Initializing state subscribe to receive addresses of connecting channels from DDS
|
||||||
// and propagate addresses of bound channels to DDS.
|
// and propagate addresses of bound channels to DDS.
|
||||||
|
@ -126,10 +119,10 @@ auto DDS::HandleControl() -> void
|
||||||
PublishBoundChannels();
|
PublishBoundChannels();
|
||||||
|
|
||||||
ChangeDeviceState(DeviceStateTransition::Connect);
|
ChangeDeviceState(DeviceStateTransition::Connect);
|
||||||
while (WaitForNextState() != DeviceState::DeviceReady) {}
|
while (fStateQueue.WaitForNext() != DeviceState::DeviceReady) {}
|
||||||
|
|
||||||
ChangeDeviceState(DeviceStateTransition::InitTask);
|
ChangeDeviceState(DeviceStateTransition::InitTask);
|
||||||
while (WaitForNextState() != DeviceState::Ready) {}
|
while (fStateQueue.WaitForNext() != DeviceState::Ready) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::Run);
|
ChangeDeviceState(DeviceStateTransition::Run);
|
||||||
|
|
||||||
// wait until stop signal
|
// wait until stop signal
|
||||||
|
@ -138,6 +131,8 @@ auto DDS::HandleControl() -> void
|
||||||
fStopCondition.wait_for(lock, chrono::seconds(1));
|
fStopCondition.wait_for(lock, chrono::seconds(1));
|
||||||
}
|
}
|
||||||
LOG(debug) << "Stopping DDS control plugin";
|
LOG(debug) << "Stopping DDS control plugin";
|
||||||
|
} catch (DeviceErrorState&) {
|
||||||
|
ReleaseDeviceControl();
|
||||||
} catch (exception& e) {
|
} catch (exception& e) {
|
||||||
LOG(error) << "Error: " << e.what() << endl;
|
LOG(error) << "Error: " << e.what() << endl;
|
||||||
return;
|
return;
|
||||||
|
@ -321,7 +316,7 @@ auto DDS::SubscribeForCustomCommands() -> void
|
||||||
} else if (cmd == "INIT DEVICE") {
|
} else if (cmd == "INIT DEVICE") {
|
||||||
if (ChangeDeviceState(ToDeviceStateTransition(cmd))) {
|
if (ChangeDeviceState(ToDeviceStateTransition(cmd))) {
|
||||||
fDDSCustomCmd.send(id + ": queued " + cmd + " transition", to_string(senderId));
|
fDDSCustomCmd.send(id + ": queued " + cmd + " transition", to_string(senderId));
|
||||||
while (WaitForNextState() != DeviceState::InitializingDevice) {}
|
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
|
||||||
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
ChangeDeviceState(DeviceStateTransition::CompleteInit);
|
||||||
} else {
|
} else {
|
||||||
fDDSCustomCmd.send(id + ": could not queue " + cmd + " transition", to_string(senderId));
|
fDDSCustomCmd.send(id + ": could not queue " + cmd + " transition", to_string(senderId));
|
||||||
|
@ -391,18 +386,6 @@ auto DDS::SubscribeForCustomCommands() -> void
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DDS::WaitForNextState() -> DeviceState
|
|
||||||
{
|
|
||||||
unique_lock<mutex> lock{fEventsMutex};
|
|
||||||
while (fEvents.empty()) {
|
|
||||||
fNewEvent.wait_for(lock, chrono::milliseconds(50));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto result = fEvents.front();
|
|
||||||
fEvents.pop();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
DDS::~DDS()
|
DDS::~DDS()
|
||||||
{
|
{
|
||||||
if (fControllerThread.joinable()) {
|
if (fControllerThread.joinable()) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <fairmq/Plugin.h>
|
#include <fairmq/Plugin.h>
|
||||||
#include <fairmq/Version.h>
|
#include <fairmq/Version.h>
|
||||||
|
#include <fairmq/StateQueue.h>
|
||||||
|
|
||||||
#include <DDS/dds_intercom.h>
|
#include <DDS/dds_intercom.h>
|
||||||
|
|
||||||
|
@ -67,7 +68,6 @@ class DDS : public Plugin
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto HandleControl() -> void;
|
auto HandleControl() -> void;
|
||||||
auto WaitForNextState() -> DeviceState;
|
|
||||||
|
|
||||||
auto FillChannelContainers() -> void;
|
auto FillChannelContainers() -> void;
|
||||||
auto SubscribeForConnectingChannels() -> void;
|
auto SubscribeForConnectingChannels() -> void;
|
||||||
|
@ -92,10 +92,8 @@ class DDS : public Plugin
|
||||||
const std::set<std::string> fTransitions;
|
const std::set<std::string> fTransitions;
|
||||||
|
|
||||||
std::thread fControllerThread;
|
std::thread fControllerThread;
|
||||||
std::queue<DeviceState> fEvents;
|
|
||||||
std::mutex fEventsMutex;
|
|
||||||
std::condition_variable fNewEvent;
|
|
||||||
DeviceState fCurrentState, fLastState;
|
DeviceState fCurrentState, fLastState;
|
||||||
|
fair::mq::StateQueue fStateQueue;
|
||||||
|
|
||||||
std::atomic<bool> fDeviceTerminationRequested;
|
std::atomic<bool> fDeviceTerminationRequested;
|
||||||
std::atomic<bool> fServiceStarted;
|
std::atomic<bool> fServiceStarted;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user