Extract state queue into own class. Use in device, plugins

This commit is contained in:
Alexey Rybalchenko
2019-07-17 15:19:08 +02:00
committed by Dennis Klein
parent 4487b81de8
commit f515eb1100
9 changed files with 159 additions and 129 deletions

View File

@@ -46,10 +46,7 @@ Control::Control(const string& name, const Plugin::Version version, const string
: Plugin(name, version, maintainer, homepage, pluginServices)
, fControllerThread()
, fSignalHandlerThread()
, fEvents()
, fEventsMutex()
, fControllerMutex()
, fNewEvent()
, fDeviceShutdownRequested(false)
, fDeviceHasShutdown(false)
, fPluginShutdownRequested(false)
@@ -57,16 +54,11 @@ Control::Control(const string& name, const Plugin::Version version, const string
SubscribeToDeviceStateChange([&](DeviceState newState) {
LOG(trace) << "control plugin notified on new state: " << newState;
{
lock_guard<mutex> lock{fEventsMutex};
fEvents.push(newState);
}
fNewEvent.notify_one();
fStateQueue.Push(newState);
if (newState == DeviceState::Error) {
fPluginShutdownRequested = 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
{
ChangeDeviceState(DeviceStateTransition::InitDevice);
while (WaitForNextState() != DeviceState::InitializingDevice) {}
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
ChangeDeviceState(DeviceStateTransition::CompleteInit);
while (WaitForNextState() != DeviceState::Initialized) {}
while (fStateQueue.WaitForNext() != DeviceState::Initialized) {}
ChangeDeviceState(DeviceStateTransition::Bind);
while (WaitForNextState() != DeviceState::Bound) {}
while (fStateQueue.WaitForNext() != DeviceState::Bound) {}
ChangeDeviceState(DeviceStateTransition::Connect);
while (WaitForNextState() != DeviceState::DeviceReady) {}
while (fStateQueue.WaitForNext() != DeviceState::DeviceReady) {}
ChangeDeviceState(DeviceStateTransition::InitTask);
while (WaitForNextState() != DeviceState::Ready) {}
while (fStateQueue.WaitForNext() != DeviceState::Ready) {}
ChangeDeviceState(DeviceStateTransition::Run);
while (WaitForNextState() != 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;
while (fStateQueue.WaitForNext() != DeviceState::Running) {}
}
auto ControlPluginProgramOptions() -> Plugin::ProgOptions
@@ -204,7 +177,7 @@ try {
case 'i':
cout << "\n --> [i] init device\n\n" << flush;
if (ChangeDeviceState(DeviceStateTransition::InitDevice)) {
while (WaitForNextState() != DeviceState::InitializingDevice) {}
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
ChangeDeviceState(DeviceStateTransition::CompleteInit);
}
break;
@@ -274,7 +247,6 @@ try {
}
if (GetCurrentDeviceState() == DeviceState::Error) {
ReleaseDeviceControl();
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.
LOG(debug) << e.what();
} catch (DeviceErrorState&) {
ReleaseDeviceControl();
}
auto Control::PrintInteractiveHelpColor() -> void
@@ -397,15 +370,10 @@ try {
{
// Wait for next state, which is DeviceState::Ready,
// or for device shutdown request (Ctrl-C)
unique_lock<mutex> lock{fEventsMutex};
while (fEvents.empty() && !fDeviceShutdownRequested) {
fNewEvent.wait_for(lock, chrono::milliseconds(50));
}
if (fEvents.front() == DeviceState::Error) {
ReleaseDeviceControl();
throw DeviceErrorState("Controlled device transitioned to error state.");
}
pair<bool, fair::mq::State> result;
do {
result = fStateQueue.WaitForNext(chrono::milliseconds(50));
} while (result.first == false && !fDeviceShutdownRequested);
}
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.
LOG(debug) << e.what();
} catch (DeviceErrorState&) {
ReleaseDeviceControl();
}
auto Control::SignalHandler() -> void
@@ -440,6 +409,7 @@ auto Control::SignalHandler() -> void
} catch (PluginServices::DeviceControlError& e) {
LOG(info) << "Graceful device shutdown failed: " << e.what() << " If hanging, hit Ctrl-C again to abort immediately.";
} catch (...) {
ReleaseDeviceControl();
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();
if (nextState != DeviceState::Error) {
EmptyEventQueue();
fStateQueue.Clear();
}
while (nextState != DeviceState::Exiting && nextState != DeviceState::Error) {
switch (nextState) {
@@ -473,19 +443,13 @@ auto Control::RunShutdownSequence() -> void
break;
}
nextState = WaitForNextState();
nextState = fStateQueue.WaitForNext();
}
fDeviceHasShutdown = true;
ReleaseDeviceControl();
}
auto Control::EmptyEventQueue() -> void
{
lock_guard<mutex> lock{fEventsMutex};
fEvents = queue<DeviceState>{};
}
Control::~Control()
{
// Notify threads to exit

View File

@@ -11,6 +11,7 @@
#include <fairmq/Plugin.h>
#include <fairmq/Version.h>
#include <fairmq/StateQueue.h>
#include <condition_variable>
#include <mutex>
@@ -41,23 +42,17 @@ class Control : public Plugin
static auto PrintStateMachineColor() -> void;
static auto PrintStateMachine() -> void;
auto StaticMode() -> void;
auto WaitForNextState() -> DeviceState;
auto SignalHandler() -> void;
auto RunShutdownSequence() -> void;
auto RunStartupSequence() -> void;
auto EmptyEventQueue() -> void;
std::thread fControllerThread;
std::thread fSignalHandlerThread;
std::queue<DeviceState> fEvents;
std::mutex fEventsMutex;
std::mutex fControllerMutex;
std::condition_variable fNewEvent;
std::atomic<bool> fDeviceShutdownRequested;
std::atomic<bool> fDeviceHasShutdown;
std::atomic<bool> fPluginShutdownRequested;
struct DeviceErrorState : std::runtime_error { using std::runtime_error::runtime_error; };
fair::mq::StateQueue fStateQueue;
}; /* class Control */
auto ControlPluginProgramOptions() -> Plugin::ProgOptions;

View File

@@ -42,9 +42,6 @@ DDS::DDS(const string& name, const Plugin::Version version, const string& mainta
, fStopCondition()
, fTransitions({ "BIND", "CONNECT", "INIT TASK", "RUN", "STOP", "RESET TASK", "RESET DEVICE" })
, fControllerThread()
, fEvents()
, fEventsMutex()
, fNewEvent()
, fCurrentState(DeviceState::Idle)
, fLastState(DeviceState::Idle)
, fDeviceTerminationRequested(false)
@@ -86,11 +83,7 @@ auto DDS::HandleControl() -> void
// subscribe to device state changes, pushing new state changes into the event queue
SubscribeToDeviceStateChange([&](DeviceState newState) {
{
lock_guard<mutex> lock{fEventsMutex};
fEvents.push(newState);
}
fNewEvent.notify_one();
fStateQueue.Push(newState);
if (newState == DeviceState::Exiting) {
fDeviceTerminationRequested = true;
}
@@ -108,11 +101,11 @@ auto DDS::HandleControl() -> void
});
ChangeDeviceState(DeviceStateTransition::InitDevice);
while (WaitForNextState() != DeviceState::InitializingDevice) {}
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
ChangeDeviceState(DeviceStateTransition::CompleteInit);
while (WaitForNextState() != DeviceState::Initialized) {}
while (fStateQueue.WaitForNext() != DeviceState::Initialized) {}
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
// and propagate addresses of bound channels to DDS.
@@ -126,10 +119,10 @@ auto DDS::HandleControl() -> void
PublishBoundChannels();
ChangeDeviceState(DeviceStateTransition::Connect);
while (WaitForNextState() != DeviceState::DeviceReady) {}
while (fStateQueue.WaitForNext() != DeviceState::DeviceReady) {}
ChangeDeviceState(DeviceStateTransition::InitTask);
while (WaitForNextState() != DeviceState::Ready) {}
while (fStateQueue.WaitForNext() != DeviceState::Ready) {}
ChangeDeviceState(DeviceStateTransition::Run);
// wait until stop signal
@@ -138,6 +131,8 @@ auto DDS::HandleControl() -> void
fStopCondition.wait_for(lock, chrono::seconds(1));
}
LOG(debug) << "Stopping DDS control plugin";
} catch (DeviceErrorState&) {
ReleaseDeviceControl();
} catch (exception& e) {
LOG(error) << "Error: " << e.what() << endl;
return;
@@ -321,7 +316,7 @@ auto DDS::SubscribeForCustomCommands() -> void
} else if (cmd == "INIT DEVICE") {
if (ChangeDeviceState(ToDeviceStateTransition(cmd))) {
fDDSCustomCmd.send(id + ": queued " + cmd + " transition", to_string(senderId));
while (WaitForNextState() != DeviceState::InitializingDevice) {}
while (fStateQueue.WaitForNext() != DeviceState::InitializingDevice) {}
ChangeDeviceState(DeviceStateTransition::CompleteInit);
} else {
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()
{
if (fControllerThread.joinable()) {

View File

@@ -11,6 +11,7 @@
#include <fairmq/Plugin.h>
#include <fairmq/Version.h>
#include <fairmq/StateQueue.h>
#include <DDS/dds_intercom.h>
@@ -67,7 +68,6 @@ class DDS : public Plugin
private:
auto HandleControl() -> void;
auto WaitForNextState() -> DeviceState;
auto FillChannelContainers() -> void;
auto SubscribeForConnectingChannels() -> void;
@@ -92,10 +92,8 @@ class DDS : public Plugin
const std::set<std::string> fTransitions;
std::thread fControllerThread;
std::queue<DeviceState> fEvents;
std::mutex fEventsMutex;
std::condition_variable fNewEvent;
DeviceState fCurrentState, fLastState;
fair::mq::StateQueue fStateQueue;
std::atomic<bool> fDeviceTerminationRequested;
std::atomic<bool> fServiceStarted;