15 #ifndef FAIRMQSTATEMACHINE_H_ 16 #define FAIRMQSTATEMACHINE_H_ 18 #define FAIRMQ_INTERFACE_VERSION 3 23 #include <condition_variable> 27 #include <unordered_map> 31 #define FUSION_MAX_VECTOR_SIZE 20 33 #include <boost/mpl/for_each.hpp> 34 #include <boost/msm/back/state_machine.hpp> 35 #include <boost/msm/back/tools.hpp> 36 #include <boost/msm/back/metafunctions.hpp> 37 #include <boost/msm/front/state_machine_def.hpp> 38 #include <boost/msm/front/functor_row.hpp> 40 #include <boost/signals2.hpp> 42 #include "FairMQLogger.h" 44 namespace msmf = boost::msm::front;
54 struct INIT_DEVICE { std::string name()
const {
return "INIT_DEVICE"; } };
56 struct INIT_TASK { std::string name()
const {
return "INIT_TASK"; } };
57 struct internal_READY { std::string name()
const {
return "internal_READY"; } };
58 struct RUN { std::string name()
const {
return "RUN"; } };
59 struct PAUSE { std::string name()
const {
return "PAUSE"; } };
60 struct STOP { std::string name()
const {
return "STOP"; } };
61 struct RESET_TASK { std::string name()
const {
return "RESET_TASK"; } };
62 struct RESET_DEVICE { std::string name()
const {
return "RESET_DEVICE"; } };
63 struct internal_IDLE { std::string name()
const {
return "internal_IDLE"; } };
64 struct END { std::string name()
const {
return "END"; } };
65 struct ERROR_FOUND { std::string name()
const {
return "ERROR_FOUND"; } };
68 #if defined(__clang__) 69 _Pragma(
"clang diagnostic push")
70 _Pragma(
"clang diagnostic ignored \"-Wnon-virtual-dtor\"")
71 #elif defined(__GNUC__) || defined(__GNUG__) 72 _Pragma(
"GCC diagnostic push")
73 _Pragma(
"GCC diagnostic ignored \"-Wnon-virtual-dtor\"")
77 struct FairMQFSM :
public msmf::state_machine_def<FairMQFSM>
84 , fWorkAvailableCondition()
85 , fWorkDoneCondition()
87 , fWorkerTerminated(
false)
89 , fWorkAvailable(
false)
90 , fStateChangeSignal()
91 , fStateChangeSignalsMap()
92 , fTerminationRequested(
false)
99 template<
typename Event,
typename FSM>
100 void on_entry(
Event const&, FSM& fsm)
102 LOG(state) <<
"Starting FairMQ state machine";
104 fsm.CallStateChangeCallbacks(IDLE);
107 fsm.fWorkerThread = std::thread(&FairMQFSM::Worker, &fsm);
110 template<
typename Event,
typename FSM>
111 void on_exit(
Event const&, FSM& )
113 LOG(state) <<
"Exiting FairMQ state machine";
132 using initial_state = boost::mpl::vector<IDLE_FSM, OK_FSM>;
137 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
138 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
140 LOG(state) <<
"Entering IDLE state";
147 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
148 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
150 fsm.fState = INITIALIZING_DEVICE;
152 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
153 while (fsm.fWorkActive)
155 fsm.fWorkDoneCondition.wait(lock);
157 fsm.fWorkAvailable =
true;
158 LOG(state) <<
"Entering INITIALIZING DEVICE state";
159 fsm.fWork = std::bind(&FairMQFSM::InitWrapper, &fsm);
160 fsm.fWorkAvailableCondition.notify_one();
166 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
167 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
169 LOG(state) <<
"Entering DEVICE READY state";
170 fsm.fState = DEVICE_READY;
176 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
177 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
179 fsm.fState = INITIALIZING_TASK;
181 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
182 while (fsm.fWorkActive)
184 fsm.fWorkDoneCondition.wait(lock);
186 fsm.fWorkAvailable =
true;
187 LOG(state) <<
"Entering INITIALIZING TASK state";
188 fsm.fWork = std::bind(&FairMQFSM::InitTaskWrapper, &fsm);
189 fsm.fWorkAvailableCondition.notify_one();
195 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
196 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
198 LOG(state) <<
"Entering READY state";
205 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
206 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
208 fsm.fState = RUNNING;
210 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
211 while (fsm.fWorkActive)
213 fsm.fWorkDoneCondition.wait(lock);
215 fsm.fWorkAvailable =
true;
216 LOG(state) <<
"Entering RUNNING state";
217 fsm.fWork = std::bind(&FairMQFSM::RunWrapper, &fsm);
218 fsm.fWorkAvailableCondition.notify_one();
224 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
225 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
230 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
231 while (fsm.fWorkActive)
233 fsm.fWorkDoneCondition.wait(lock);
235 fsm.fWorkAvailable =
true;
236 LOG(state) <<
"Entering PAUSED state";
237 fsm.fWork = std::bind(&FairMQFSM::PauseWrapper, &fsm);
238 fsm.fWorkAvailableCondition.notify_one();
244 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
245 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
247 fsm.fState = RUNNING;
249 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
250 while (fsm.fWorkActive)
252 fsm.fWorkDoneCondition.wait(lock);
254 fsm.fWorkAvailable =
true;
255 LOG(state) <<
"Entering RUNNING state";
256 fsm.fWork = std::bind(&FairMQFSM::RunWrapper, &fsm);
257 fsm.fWorkAvailableCondition.notify_one();
263 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
264 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
269 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
270 while (fsm.fWorkActive)
272 fsm.fWorkDoneCondition.wait(lock);
274 LOG(state) <<
"Entering READY state";
280 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
281 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
285 LOG(state) <<
"RUNNING state finished without an external event, entering READY state";
291 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
292 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
294 fsm.fState = RESETTING_TASK;
296 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
297 while (fsm.fWorkActive)
299 fsm.fWorkDoneCondition.wait(lock);
301 fsm.fWorkAvailable =
true;
302 LOG(state) <<
"Entering RESETTING TASK state";
303 fsm.fWork = std::bind(&FairMQFSM::ResetTaskWrapper, &fsm);
304 fsm.fWorkAvailableCondition.notify_one();
310 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
311 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
313 fsm.fState = RESETTING_DEVICE;
315 std::unique_lock<std::mutex> lock(fsm.fWorkMutex);
316 while (fsm.fWorkActive)
318 fsm.fWorkDoneCondition.wait(lock);
320 fsm.fWorkAvailable =
true;
321 LOG(state) <<
"Entering RESETTING DEVICE state";
322 fsm.fWork = std::bind(&FairMQFSM::ResetWrapper, &fsm);
323 fsm.fWorkAvailableCondition.notify_one();
329 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
330 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
332 LOG(state) <<
"Entering EXITING state";
333 fsm.fState = EXITING;
334 fsm.fTerminationRequested =
true;
335 fsm.CallStateChangeCallbacks(EXITING);
339 std::lock_guard<std::mutex> lock(fsm.fWorkMutex);
340 fsm.fWorkerTerminated =
true;
341 fsm.fWorkAvailableCondition.notify_one();
345 if (fsm.fWorkerThread.joinable())
347 fsm.fWorkerThread.join();
356 template<
typename EVT,
typename FSM,
typename SourceState,
typename TargetState>
357 void operator()(EVT
const&, FSM& fsm, SourceState&, TargetState&)
359 LOG(state) <<
"Entering ERROR state";
361 fsm.CallStateChangeCallbacks(Error);
368 msmf::Row<IDLE_FSM, INIT_DEVICE, INITIALIZING_DEVICE_FSM, InitDeviceFct, msmf::none>,
369 msmf::Row<IDLE_FSM, END, EXITING_FSM, ExitingFct, msmf::none>,
370 msmf::Row<INITIALIZING_DEVICE_FSM, internal_DEVICE_READY, DEVICE_READY_FSM, DeviceReadyFct, msmf::none>,
371 msmf::Row<DEVICE_READY_FSM, INIT_TASK, INITIALIZING_TASK_FSM, InitTaskFct, msmf::none>,
372 msmf::Row<DEVICE_READY_FSM, RESET_DEVICE, RESETTING_DEVICE_FSM, ResetDeviceFct, msmf::none>,
373 msmf::Row<INITIALIZING_TASK_FSM, internal_READY, READY_FSM, ReadyFct, msmf::none>,
374 msmf::Row<READY_FSM, RUN, RUNNING_FSM, RunFct, msmf::none>,
375 msmf::Row<READY_FSM, RESET_TASK, RESETTING_TASK_FSM, ResetTaskFct, msmf::none>,
376 msmf::Row<RUNNING_FSM, PAUSE, PAUSED_FSM, PauseFct, msmf::none>,
377 msmf::Row<RUNNING_FSM, STOP, READY_FSM, StopFct, msmf::none>,
378 msmf::Row<RUNNING_FSM, internal_READY, READY_FSM, InternalStopFct, msmf::none>,
379 msmf::Row<PAUSED_FSM, RUN, RUNNING_FSM, ResumeFct, msmf::none>,
380 msmf::Row<RESETTING_TASK_FSM, internal_DEVICE_READY, DEVICE_READY_FSM, DeviceReadyFct, msmf::none>,
381 msmf::Row<RESETTING_DEVICE_FSM, internal_IDLE, IDLE_FSM, IdleFct, msmf::none>,
382 msmf::Row<OK_FSM, ERROR_FOUND, ERROR_FSM, ErrorFoundFct, msmf::none>>
386 template<
typename FSM,
typename Event>
387 void no_transition(
Event const& e, FSM&,
int state)
389 using recursive_stt =
typename boost::msm::back::recursive_get_transition_table<FSM>::type;
390 using all_states =
typename boost::msm::back::generate_state_set<recursive_stt>::type;
392 std::string stateName;
394 boost::mpl::for_each<all_states, boost::msm::wrap<boost::mpl::placeholders::_1>>(boost::msm::back::get_state_name<recursive_stt>(stateName, state));
396 stateName = stateName.substr(24);
397 std::size_t pos = stateName.find(
"_FSME");
398 stateName.erase(pos);
400 if (stateName ==
"1RUNNING" || stateName ==
"6DEVICE_READY" || stateName ==
"0PAUSED" || stateName ==
"8RESETTING_TASK" || stateName ==
"0RESETTING_DEVICE")
402 stateName = stateName.substr(1);
405 if (stateName !=
"OK")
407 LOG(state) <<
"No transition from state " << stateName <<
" on event " << e.name();
430 static std::string GetStateName(
const int state)
440 case INITIALIZING_DEVICE:
441 return "INITIALIZING_DEVICE";
443 return "DEVICE_READY";
444 case INITIALIZING_TASK:
445 return "INITIALIZING_TASK";
453 return "RESETTING_TASK";
454 case RESETTING_DEVICE:
455 return "RESETTING_DEVICE";
459 return "requested name for non-existent state...";
463 std::string GetCurrentStateName()
const 465 return GetStateName(fState);
467 int GetCurrentState()
const 471 bool CheckCurrentState(
int state)
const 473 return state == fState;
475 bool CheckCurrentState(std::string state)
const 477 return state == GetCurrentStateName();
481 virtual void InitWrapper() {}
482 virtual void InitTaskWrapper() {}
483 virtual void RunWrapper() {}
484 virtual void PauseWrapper() {}
485 virtual void ResetWrapper() {}
486 virtual void ResetTaskWrapper() {}
487 virtual void Exit() {}
488 virtual void Unblock() {}
492 return fTerminationRequested;
496 std::atomic<State> fState;
497 std::mutex fChangeStateMutex;
500 std::function<void(void)> fWork;
501 std::condition_variable fWorkAvailableCondition;
502 std::condition_variable fWorkDoneCondition;
503 std::mutex fWorkMutex;
504 bool fWorkerTerminated;
508 boost::signals2::signal<void(const State)> fStateChangeSignal;
509 std::unordered_map<std::string, boost::signals2::connection> fStateChangeSignalsMap;
510 std::atomic<bool> fTerminationRequested;
512 void CallStateChangeCallbacks(
const State state)
const 514 if (!fStateChangeSignal.empty())
516 fStateChangeSignal(state);
526 std::unique_lock<std::mutex> lock(fWorkMutex);
528 while (!fWorkAvailable && !fWorkerTerminated)
530 fWorkAvailableCondition.wait(lock);
533 if (fWorkerTerminated)
544 std::lock_guard<std::mutex> lock(fWorkMutex);
546 fWorkAvailable =
false;
547 fWorkDoneCondition.notify_one();
549 CallStateChangeCallbacks(fState);
554 std::thread fWorkerThread;
558 #if defined(__clang__) 559 _Pragma(
"clang diagnostic pop")
560 #elif defined(__GNUC__) || defined(__GNUG__) 561 _Pragma(
"GCC diagnostic pop")
574 internal_DEVICE_READY,
590 int GetInterfaceVersion()
const;
592 bool ChangeState(
int event);
593 bool ChangeState(
const std::string& event);
595 void WaitForEndOfState(
int event);
596 void WaitForEndOfState(
const std::string& event);
598 bool WaitForEndOfStateForMs(
int event,
int durationInMs);
599 bool WaitForEndOfStateForMs(
const std::string& event,
int durationInMs);
601 void SubscribeToStateChange(
const std::string& key, std::function<
void(
const State)> callback);
602 void UnsubscribeFromStateChange(
const std::string& key);
605 int GetEventNumber(
const std::string& event);
Definition: FairMQStateMachine.h:145
Definition: FairMQStateMachine.h:61
Definition: FairMQStateMachine.h:126
Definition: FairMQStateMachine.h:58
Definition: FairMQStateMachine.h:308
Definition: FairMQStateMachine.h:63
Definition: FairMQStateMachine.h:120
Definition: FairMQStateMachine.h:56
Definition: FairMQStateMachine.h:261
Definition: FairMQStateMachine.h:54
Definition: EventManager.h:33
Definition: FairMQStateMachine.h:129
Definition: FairMQStateMachine.h:59
Definition: FairMQStateMachine.h:65
Definition: FairMQStateMachine.h:123
Definition: FairMQStateMachine.h:327
Definition: FairMQStateMachine.h:242
Definition: FairMQStateMachine.h:121
Definition: FairMQStateMachine.h:164
Definition: FairMQStateMachine.h:135
Definition: FairMQStateMachine.h:354
Definition: FairMQStateMachine.h:193
Definition: FairMQStateMachine.h:278
Definition: FairMQStateMachine.h:62
Definition: FairMQStateMachine.h:127
Definition: FairMQStateMachine.h:366
Definition: FairMQStateMachine.h:122
Definition: FairMQStateMachine.h:174
Definition: FairMQStateMachine.h:568
Definition: FairMQStateMachine.h:118
Definition: FairMQStateMachine.h:55
Definition: FairMQStateMachine.h:57
Definition: FairMQStateMachine.h:289
Definition: FairMQStateMachine.h:222
Definition: FairMQStateMachine.h:64
Definition: FairMQStateMachine.h:124
Definition: DeviceRunner.h:23
Definition: FairMQStateMachine.h:203
Definition: FairMQStateMachine.h:125
Definition: FairMQStateMachine.h:60
Definition: FairMQStateMachine.h:128
Definition: FairMQStateMachine.h:117
Definition: FairMQStateMachine.h:77