[idea] An emergency stop of SOEnv on an exception in noexcept context
eao197 opened this issue · comments
There are several noexcept contexts where exceptions are prohibited. For example: on_enter/on_exit handlers for states, not_empty_notificator for mchains. But actions that can throw are often used in such contexts, for example:
st_free.on_enter( [this]() noexcept {
so_5::send<msg_check_new_load>(*this);
});
A call to so_5::send
may throw. If such an exception won't be intercepted, the whole application will crash (due to std::terminate
call).
For some types of applications it's a normal behavior. But not always. For example, it's not good to crash a complex GUI application if one so_5::send
fails. But it's also not good to just ignore such a problem by using something like that:
st_free.on_enter( [this]() noexcept {
try {
so_5::send<msg_check_new_load>(*this);
} catch(...) {} // Discard the exception.
});
Maybe the better way is to stop the SObjectizer Environment. Something like:
st_free.on_enter( [this]() noexcept {
try {
so_5::send<msg_check_new_load>(*this);
} catch(...) {
so_environment().stop();
}
});
But there are some open questions:
Is it always possible to call so_environment_t::stop()
? Especially when it's called from state's on_enter/on_exit handlers.
The source code of SObjectizer has to be examined.
It's better to have some helper function that takes a lambda than can throw and wraps it into a noexcept function object that catches exceptions and calls so_environment_t::stop()
. Something like:
st_free.on_enter( so_environment().make_stopper_on_exception(
[this]() {
so_5::send<msg_check_new_load>(*this);
} ) );
Or something like (an additional form of on_enter/on_exit method):
st_free.on_enter( so_5::stop_env_on_exception,
[this]() {
so_5::send<msg_check_new_load>(*this);
} ) );
It will be good to store and then access somehow the reason for the environment's shutdown.
Unfortunately, I have no idea what it can look like. But, obviously, such a feature has to be noexcept (so we can't store std::string or another type that can allocate, maybe an object with std::array<char, N>
inside, where N will be reasonably long).
Is it always possible to call so_environment_t::stop()? Especially when it's called from state's on_enter/on_exit handlers.
It seems that calling so_environment_t::stop()
from on_enter/on_exit handlers isn't a problem.