mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 00:31:14 +00:00
feat: Improve ChangeState
API
* Add `[[nodiscard]]` to `bool Device::ChangeState()` * Introduce throwing variant `void Device::ChangeStateOrThrow()` resolves #441
This commit is contained in:
parent
5ef17fddbb
commit
435d07eaf9
|
@ -164,30 +164,30 @@ void Device::TransitionTo(State s)
|
||||||
while (s != currentState) {
|
while (s != currentState) {
|
||||||
switch (currentState) {
|
switch (currentState) {
|
||||||
case State::Idle:
|
case State::Idle:
|
||||||
if (s == State::Exiting) { ChangeState(Transition::End); }
|
if (s == State::Exiting) { ChangeStateOrThrow(Transition::End); }
|
||||||
else { ChangeState(Transition::InitDevice); }
|
else { ChangeStateOrThrow(Transition::InitDevice); }
|
||||||
break;
|
break;
|
||||||
case State::InitializingDevice:
|
case State::InitializingDevice:
|
||||||
ChangeState(Transition::CompleteInit);
|
ChangeStateOrThrow(Transition::CompleteInit);
|
||||||
break;
|
break;
|
||||||
case State::Initialized:
|
case State::Initialized:
|
||||||
if (s == State::Exiting || s == State::Idle) { ChangeState(Transition::ResetDevice); }
|
if (s == State::Exiting || s == State::Idle) { ChangeStateOrThrow(Transition::ResetDevice); }
|
||||||
else { ChangeState(Transition::Bind); }
|
else { ChangeStateOrThrow(Transition::Bind); }
|
||||||
break;
|
break;
|
||||||
case State::Bound:
|
case State::Bound:
|
||||||
if (s == State::DeviceReady || s == State::Ready || s == State::Running) { ChangeState(Transition::Connect); }
|
if (s == State::DeviceReady || s == State::Ready || s == State::Running) { ChangeStateOrThrow(Transition::Connect); }
|
||||||
else { ChangeState(Transition::ResetDevice); }
|
else { ChangeStateOrThrow(Transition::ResetDevice); }
|
||||||
break;
|
break;
|
||||||
case State::DeviceReady:
|
case State::DeviceReady:
|
||||||
if (s == State::Running || s == State::Ready) { ChangeState(Transition::InitTask); }
|
if (s == State::Running || s == State::Ready) { ChangeStateOrThrow(Transition::InitTask); }
|
||||||
else { ChangeState(Transition::ResetDevice); }
|
else { ChangeStateOrThrow(Transition::ResetDevice); }
|
||||||
break;
|
break;
|
||||||
case State::Ready:
|
case State::Ready:
|
||||||
if (s == State::Running) { ChangeState(Transition::Run); }
|
if (s == State::Running) { ChangeStateOrThrow(Transition::Run); }
|
||||||
else { ChangeState(Transition::ResetTask); }
|
else { ChangeStateOrThrow(Transition::ResetTask); }
|
||||||
break;
|
break;
|
||||||
case State::Running:
|
case State::Running:
|
||||||
ChangeState(Transition::Stop);
|
ChangeStateOrThrow(Transition::Stop);
|
||||||
break;
|
break;
|
||||||
case State::Binding:
|
case State::Binding:
|
||||||
case State::Connecting:
|
case State::Connecting:
|
||||||
|
@ -281,7 +281,7 @@ void Device::InitWrapper()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeState(Transition::Auto);
|
// ChangeStateOrThrow(Transition::Auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::BindWrapper()
|
void Device::BindWrapper()
|
||||||
|
@ -298,7 +298,7 @@ void Device::BindWrapper()
|
||||||
Bind();
|
Bind();
|
||||||
|
|
||||||
if (!NewStatePending()) {
|
if (!NewStatePending()) {
|
||||||
ChangeState(Transition::Auto);
|
ChangeStateOrThrow(Transition::Auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ void Device::ConnectWrapper()
|
||||||
Connect();
|
Connect();
|
||||||
|
|
||||||
if (!NewStatePending()) {
|
if (!NewStatePending()) {
|
||||||
ChangeState(Transition::Auto);
|
ChangeStateOrThrow(Transition::Auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +443,7 @@ void Device::InitTaskWrapper()
|
||||||
InitTask();
|
InitTask();
|
||||||
|
|
||||||
if (!NewStatePending()) {
|
if (!NewStatePending()) {
|
||||||
ChangeState(Transition::Auto);
|
ChangeStateOrThrow(Transition::Auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +466,7 @@ void Device::RunWrapper()
|
||||||
|
|
||||||
// change to Error state in case of an exception, to release LogSocketRates
|
// change to Error state in case of an exception, to release LogSocketRates
|
||||||
tools::CallOnDestruction cod([&](){
|
tools::CallOnDestruction cod([&](){
|
||||||
ChangeState(Transition::ErrorFound);
|
ChangeStateOrThrow(Transition::ErrorFound);
|
||||||
});
|
});
|
||||||
|
|
||||||
PreRun();
|
PreRun();
|
||||||
|
@ -493,7 +493,7 @@ void Device::RunWrapper()
|
||||||
|
|
||||||
// if Run() exited and the state is still RUNNING, transition to READY.
|
// if Run() exited and the state is still RUNNING, transition to READY.
|
||||||
if (!NewStatePending()) {
|
if (!NewStatePending()) {
|
||||||
ChangeState(Transition::Stop);
|
ChangeStateOrThrow(Transition::Stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
PostRun();
|
PostRun();
|
||||||
|
@ -794,7 +794,7 @@ void Device::ResetTaskWrapper()
|
||||||
ResetTask();
|
ResetTask();
|
||||||
|
|
||||||
if (!NewStatePending()) {
|
if (!NewStatePending()) {
|
||||||
ChangeState(Transition::Auto);
|
ChangeStateOrThrow(Transition::Auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +813,7 @@ void Device::ResetWrapper()
|
||||||
GetChannels().clear();
|
GetChannels().clear();
|
||||||
fTransportFactory.reset();
|
fTransportFactory.reset();
|
||||||
if (!NewStatePending()) {
|
if (!NewStatePending()) {
|
||||||
ChangeState(Transition::Auto);
|
ChangeStateOrThrow(Transition::Auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
// FairMQ
|
// FairMQ
|
||||||
#include <fairmq/Channel.h>
|
#include <fairmq/Channel.h>
|
||||||
|
#include <fairmq/Error.h>
|
||||||
#include <fairmq/Message.h>
|
#include <fairmq/Message.h>
|
||||||
#include <fairmq/Parts.h>
|
#include <fairmq/Parts.h>
|
||||||
#include <fairmq/ProgOptions.h>
|
#include <fairmq/ProgOptions.h>
|
||||||
|
@ -498,21 +499,49 @@ class Device
|
||||||
public:
|
public:
|
||||||
/// @brief Request a device state transition
|
/// @brief Request a device state transition
|
||||||
/// @param transition state transition
|
/// @param transition state transition
|
||||||
|
/// @return whether the transition was successfully scheduled
|
||||||
///
|
///
|
||||||
/// The state transition may not happen immediately, but when the current state evaluates the
|
/// The state transition may not happen immediately, but when the current state evaluates the
|
||||||
/// pending transition event and terminates. In other words, the device states are scheduled
|
/// pending transition event and terminates. In other words, the device states are scheduled
|
||||||
/// cooperatively.
|
/// cooperatively.
|
||||||
bool ChangeState(const Transition transition) { return fStateMachine.ChangeState(transition); }
|
[[nodiscard]] bool ChangeState(const Transition transition)
|
||||||
|
{
|
||||||
|
return fStateMachine.ChangeState(transition);
|
||||||
|
}
|
||||||
/// @brief Request a device state transition
|
/// @brief Request a device state transition
|
||||||
/// @param transition state transition
|
/// @param transition state transition
|
||||||
|
/// @return whether the transition was successfully scheduled
|
||||||
///
|
///
|
||||||
/// The state transition may not happen immediately, but when the current state evaluates the
|
/// The state transition may not happen immediately, but when the current state evaluates the
|
||||||
/// pending transition event and terminates. In other words, the device states are scheduled
|
/// pending transition event and terminates. In other words, the device states are scheduled
|
||||||
/// cooperatively.
|
/// cooperatively.
|
||||||
bool ChangeState(const std::string& transition)
|
[[nodiscard]] bool ChangeState(const std::string& transition)
|
||||||
{
|
{
|
||||||
return fStateMachine.ChangeState(GetTransition(transition));
|
return fStateMachine.ChangeState(GetTransition(transition));
|
||||||
}
|
}
|
||||||
|
/// @brief Request a device state transition
|
||||||
|
/// @param transition state transition
|
||||||
|
/// @throws when the transition could not have been scheduled
|
||||||
|
///
|
||||||
|
/// Throwing version of Device::ChangeState().
|
||||||
|
void ChangeStateOrThrow(Transition transition)
|
||||||
|
{
|
||||||
|
if(!ChangeState(transition)) {
|
||||||
|
auto const err = MakeErrorCode(ErrorCode::DeviceChangeStateFailed);
|
||||||
|
throw std::system_error(err.value(),
|
||||||
|
err.category(),
|
||||||
|
tools::ToString("Invalid transition: ", transition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// @brief Request a device state transition
|
||||||
|
/// @param transition state transition
|
||||||
|
/// @throws when the transition could not have been scheduled
|
||||||
|
///
|
||||||
|
/// Throwing version of Device::ChangeState().
|
||||||
|
void ChangeStateOrThrow(std::string const& transition)
|
||||||
|
{
|
||||||
|
ChangeStateOrThrow(GetTransition(transition));
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief waits for the next state (any) to occur
|
/// @brief waits for the next state (any) to occur
|
||||||
State WaitForNextState() { return fStateQueue.WaitForNext(); }
|
State WaitForNextState() { return fStateQueue.WaitForNext(); }
|
||||||
|
|
|
@ -152,7 +152,7 @@ auto DeviceRunner::Run() -> int
|
||||||
fDevice->RegisterChannelEndpoints();
|
fDevice->RegisterChannelEndpoints();
|
||||||
if (fConfig.Count("print-channels")) {
|
if (fConfig.Count("print-channels")) {
|
||||||
fDevice->PrintRegisteredChannels();
|
fDevice->PrintRegisteredChannels();
|
||||||
fDevice->ChangeState(fair::mq::Transition::End);
|
fDevice->ChangeStateOrThrow(fair::mq::Transition::End);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ auto DeviceRunner::Run() -> int
|
||||||
if (fConfig.Count("version")) {
|
if (fConfig.Count("version")) {
|
||||||
LOGV(info, verylow) << "FairMQ version: " << FAIRMQ_GIT_VERSION;
|
LOGV(info, verylow) << "FairMQ version: " << FAIRMQ_GIT_VERSION;
|
||||||
LOGV(info, verylow) << "User device version: " << fDevice->GetVersion();
|
LOGV(info, verylow) << "User device version: " << fDevice->GetVersion();
|
||||||
fDevice->ChangeState(fair::mq::Transition::End);
|
fDevice->ChangeStateOrThrow(fair::mq::Transition::End);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,4 +97,26 @@ TEST(Transitions, ConcurrentTransitionTos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Transitions, InvalidChangeState)
|
||||||
|
{
|
||||||
|
Device device;
|
||||||
|
thread t([&] { device.RunStateMachine(); });
|
||||||
|
|
||||||
|
ASSERT_FALSE(device.ChangeState(Transition::Connect));
|
||||||
|
|
||||||
|
ASSERT_TRUE(device.ChangeState(Transition::End));
|
||||||
|
if (t.joinable()) { t.join(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Transitions, InvalidChangeStateOrThrow)
|
||||||
|
{
|
||||||
|
Device device;
|
||||||
|
thread t([&] { device.RunStateMachine(); });
|
||||||
|
|
||||||
|
ASSERT_THROW(device.ChangeStateOrThrow(Transition::Connect), std::system_error);
|
||||||
|
|
||||||
|
ASSERT_NO_THROW(device.ChangeStateOrThrow(Transition::End));
|
||||||
|
if (t.joinable()) { t.join(); }
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue
Block a user