Skip to content

Gco/fix double exit processing #370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 25 additions & 59 deletions include/boost/sml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -856,18 +856,8 @@ template <class T>
struct transitions<T> {
template <class TEvent, class SM, class TDeps, class TSubs>
static bool execute(const TEvent &event, SM &sm, TDeps &deps, TSubs &subs, typename SM::state_t &current_state) {
return execute_impl(event, sm, deps, subs, current_state);
}
template <class TEvent, class SM, class TDeps, class TSubs>
static bool execute_impl(const TEvent &event, SM &sm, TDeps &deps, TSubs &subs, typename SM::state_t &current_state) {
return aux::get<T>(sm.transitions_).execute(event, sm, deps, subs, current_state, typename SM::has_entry_exits{});
}
template <class _, class TEvent, class SM, class TDeps, class TSubs>
static bool execute_impl(const on_exit<_, TEvent> &event, SM &sm, TDeps &deps, TSubs &subs,
typename SM::state_t &current_state) {
aux::get<T>(sm.transitions_).execute(event, sm, deps, subs, current_state, typename SM::has_entry_exits{});
return false;
}
};
template <>
struct transitions<aux::true_type> {
Expand Down Expand Up @@ -910,12 +900,23 @@ struct transitions_sub<sm<TSM>, T, Ts...> {
sub_sm<sm_impl<TSM>>::get(&subs).process_event(event, deps, subs);
return true;
}
template <class _, class TEvent, class SM, class TDeps, class TSubs>
static bool execute_impl(const back::on_exit<_, TEvent> &event, SM &sm, TDeps &deps, TSubs &subs,
typename SM::state_t &current_state) {
sub_sm<sm_impl<TSM>>::get(&subs).process_event(event, deps, subs);
transitions<T, Ts...>::execute(event, sm, deps, subs, current_state);
return true;
}
};
template <class TSM>
struct transitions_sub<sm<TSM>> {
template <class TEvent, class SM, class TDeps, class TSubs>
static bool execute(const TEvent &event, SM &, TDeps &deps, TSubs &subs, typename SM::state_t &) {
return sub_sm<sm_impl<TSM>>::get(&subs).template process_event<TEvent>(event, deps, subs);
return sub_sm<sm_impl<TSM>>::get(&subs).process_event(event, deps, subs);
}
template <class, class SM, class TDeps, class TSubs>
static bool execute(const anonymous &, SM &, TDeps &, TSubs &, typename SM::state_t &) {
return false;
}
};
} // namespace back
Expand Down Expand Up @@ -1336,20 +1337,13 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
}
template <class TEvent, class TDeps, class TSubs>
bool process_event(const TEvent &event, TDeps &deps, TSubs &subs) {
policies::log_process_event<sm_t>(aux::type<logger_t>{}, deps, event);
#if BOOST_SML_DISABLE_EXCEPTIONS
const auto handled = process_event_impl<get_event_mapping_t<get_generic_t<TEvent>, mappings>>(
event, deps, subs, states_t{}, aux::make_index_sequence<regions>{});
#else
const auto handled =
process_event_noexcept<get_event_mapping_t<get_generic_t<TEvent>, mappings>>(event, deps, subs, has_exceptions{});
#endif
bool handled = process_internal_events(event, deps, subs);
do {
while (process_internal_events(anonymous{}, deps, subs)) {
}
process_defer_events(deps, subs, handled, aux::type<defer_queue_t<TEvent>>{}, events_t{});
} while (process_queued_events(deps, subs, aux::type<process_queue_t<TEvent>>{}, events_t{}) ||
process_internal_events(anonymous{}, deps, subs));
do {
while (process_internal_events(anonymous{}, deps, subs)) {
}
} while (process_defer_events(deps, subs, handled, aux::type<defer_queue_t<TEvent>>{}, events_t{}));
} while (process_queued_events(deps, subs, aux::type<process_queue_t<TEvent>>{}, events_t{}));
return handled;
}
void initialize(const aux::type_list<> &) {}
Expand All @@ -1368,13 +1362,7 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
}
template <class TDeps, class TSubs>
void start(TDeps &deps, TSubs &subs) {
process_internal_events(on_entry<_, initial>{}, deps, subs);
do {
while (process_internal_events(anonymous{}, deps, subs)) {
}
process_defer_events(deps, subs, true, aux::type<defer_queue_t<initial>>{}, events_t{});
} while (process_queued_events(deps, subs, aux::type<process_queue_t<initial>>{}, events_t{}) ||
process_internal_events(anonymous{}, deps, subs));
process_event(on_entry<_, initial>{}, deps, subs);
}
template <class TEvent, class TDeps, class TSubs, class... Ts,
__BOOST_SML_REQUIRES(!aux::is_base_of<get_generic_t<TEvent>, events_ids_t>::value &&
Expand Down Expand Up @@ -1458,15 +1446,15 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
aux::index_sequence<Ns...>) {
const auto lock = thread_safety_.create_lock();
(void)lock;
auto handled = false;
#if defined(__cpp_fold_expressions)
return ((dispatch_t::template dispatch<0, TMappings>(*this, current_state_[Ns], event, deps, subs, states)), ...);
((handled |= dispatch_t::template dispatch<0, TMappings>(*this, current_state_[Ns], event, deps, subs, states)), ...);
#else
auto handled = false;
(void)aux::swallow{
0,
(handled |= dispatch_t::template dispatch<0, TMappings>(*this, current_state_[Ns], event, deps, subs, states), 0)...};
return handled;
#endif
return handled;
}
template <class TMappings, class TEvent, class TDeps, class TSubs, class... TStates>
bool process_event_impl(const TEvent &event, TDeps &deps, TSubs &subs, const aux::type_list<TStates...> &states,
Expand Down Expand Up @@ -1522,15 +1510,10 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
template <class TDeps, class TSubs, class TEvent>
bool process_event_no_defer(TDeps &deps, TSubs &subs, const void *data) {
const auto &event = *static_cast<const TEvent *>(data);
policies::log_process_event<sm_t>(aux::type<logger_t>{}, deps, event);
#if BOOST_SML_DISABLE_EXCEPTIONS
const auto handled = process_event_impl<get_event_mapping_t<TEvent, mappings>>(event, deps, subs, states_t{},
aux::make_index_sequence<regions>{});
#else
const auto handled = process_event_noexcept<get_event_mapping_t<TEvent, mappings>>(event, deps, subs, has_exceptions{});
#endif
bool handled = process_internal_events(event, deps, subs);
if (handled && defer_again_) {
++defer_it_;
return false;
} else {
defer_.erase(defer_it_);
defer_it_ = defer_.begin();
Expand All @@ -1550,9 +1533,8 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
defer_again_ = false;
defer_it_ = defer_.begin();
defer_end_ = defer_.end();
processed_events = defer_it_ != defer_end_;
while (defer_it_ != defer_end_) {
(this->*dispatch_table[defer_it_->id])(deps, subs, defer_it_->data);
processed_events |= (this->*dispatch_table[defer_it_->id])(deps, subs, defer_it_->data);
defer_again_ = false;
}
defer_processing_ = false;
Expand Down Expand Up @@ -2404,14 +2386,6 @@ void update_current_state(SM &, TDeps &deps, TSubs &subs, typename SM::state_t &
update_composite_states<back::sm_impl<T>>(subs, typename back::sm_impl<T>::has_history_states{},
typename back::sm_impl<T>::history_states_t{});
}
template <class TDeps, class TSubs, class TDstState>
void process_internal_transitions(TDeps &, TSubs &, const TDstState &) {}
template <class TDeps, class TSubs, class T>
void process_internal_transitions(TDeps &deps, TSubs &subs, const state<back::sm<T>> &) {
auto &sm = back::sub_sm<back::sm_impl<T>>::get(&subs);
while (sm.process_internal_events(back::anonymous{}, deps, subs)) {
}
}
template <class S1, class S2, class E, class G, class A>
struct transition<state<S1>, state<S2>, front::event<E>, G, A> {
static constexpr auto initial = state<S2>::initial;
Expand All @@ -2432,7 +2406,6 @@ struct transition<state<S1>, state<S2>, front::event<E>, G, A> {
state<dst_state>{});
call<TEvent, args_t<A, TEvent>, typename SM::logger_t>::execute(a, event, sm, deps, subs);
sm.process_internal_event(back::on_entry<back::_, TEvent>{event}, deps, subs, current_state);
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
return false;
Expand All @@ -2444,7 +2417,6 @@ struct transition<state<S1>, state<S2>, front::event<E>, G, A> {
aux::get_id<typename SM::state_t, dst_state>((typename SM::states_ids_t *)0), state<src_state>{},
state<dst_state>{});
call<TEvent, args_t<A, TEvent>, typename SM::logger_t>::execute(a, event, sm, deps, subs);
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
return false;
Expand Down Expand Up @@ -2493,7 +2465,6 @@ struct transition<state<S1>, state<S2>, front::event<E>, always, A> {
state<dst_state>{});
call<TEvent, args_t<A, TEvent>, typename SM::logger_t>::execute(a, event, sm, deps, subs);
sm.process_internal_event(back::on_entry<back::_, TEvent>{event}, deps, subs, current_state);
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
template <class TEvent, class SM, class TDeps, class TSubs>
Expand All @@ -2502,7 +2473,6 @@ struct transition<state<S1>, state<S2>, front::event<E>, always, A> {
aux::get_id<typename SM::state_t, dst_state>((typename SM::states_ids_t *)0), state<src_state>{},
state<dst_state>{});
call<TEvent, args_t<A, TEvent>, typename SM::logger_t>::execute(a, event, sm, deps, subs);
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
A a;
Expand Down Expand Up @@ -2544,7 +2514,6 @@ struct transition<state<S1>, state<S2>, front::event<E>, G, none> {
aux::get_id<typename SM::state_t, dst_state>((typename SM::states_ids_t *)0), state<src_state>{},
state<dst_state>{});
sm.process_internal_event(back::on_entry<back::_, TEvent>{event}, deps, subs, current_state);
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
return false;
Expand All @@ -2555,7 +2524,6 @@ struct transition<state<S1>, state<S2>, front::event<E>, G, none> {
update_current_state(sm, deps, subs, current_state,
aux::get_id<typename SM::state_t, dst_state>((typename SM::states_ids_t *)0), state<src_state>{},
state<dst_state>{});
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
return false;
Expand Down Expand Up @@ -2597,15 +2565,13 @@ struct transition<state<S1>, state<S2>, front::event<E>, always, none> {
aux::get_id<typename SM::state_t, dst_state>((typename SM::states_ids_t *)0), state<src_state>{},
state<dst_state>{});
sm.process_internal_event(back::on_entry<back::_, TEvent>{event}, deps, subs, current_state);
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
template <class TEvent, class SM, class TDeps, class TSubs>
bool execute(const TEvent &, SM &sm, TDeps &deps, TSubs &subs, typename SM::state_t &current_state, aux::false_type) {
update_current_state(sm, deps, subs, current_state,
aux::get_id<typename SM::state_t, dst_state>((typename SM::states_ids_t *)0), state<src_state>{},
state<dst_state>{});
process_internal_transitions(deps, subs, state<dst_state>{});
return true;
}
__BOOST_SML_ZERO_SIZE_ARRAY(aux::byte);
Expand Down
46 changes: 14 additions & 32 deletions include/boost/sml/back/state_machine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,15 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:

template <class TEvent, class TDeps, class TSubs>
bool process_event(const TEvent &event, TDeps &deps, TSubs &subs) {
policies::log_process_event<sm_t>(aux::type<logger_t>{}, deps, event);
bool handled = process_internal_events(event, deps, subs);

#if BOOST_SML_DISABLE_EXCEPTIONS // __pph__
const auto handled = process_event_impl<get_event_mapping_t<get_generic_t<TEvent>, mappings>>(
event, deps, subs, states_t{}, aux::make_index_sequence<regions>{});
#else // __pph__
const auto handled =
process_event_noexcept<get_event_mapping_t<get_generic_t<TEvent>, mappings>>(event, deps, subs, has_exceptions{});
#endif // __pph__
// Repeat internal transition until there is no more to process.
do {
while (process_internal_events(anonymous{}, deps, subs)) {
}
process_defer_events(deps, subs, handled, aux::type<defer_queue_t<TEvent>>{}, events_t{});
} while (process_queued_events(deps, subs, aux::type<process_queue_t<TEvent>>{}, events_t{}) ||
process_internal_events(anonymous{}, deps, subs));
do {
while (process_internal_events(anonymous{}, deps, subs)) {
}
} while (process_defer_events(deps, subs, handled, aux::type<defer_queue_t<TEvent>>{}, events_t{}));
} while (process_queued_events(deps, subs, aux::type<process_queue_t<TEvent>>{}, events_t{}));

return handled;
}
Expand All @@ -116,13 +109,7 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:

template <class TDeps, class TSubs>
void start(TDeps &deps, TSubs &subs) {
process_internal_events(on_entry<_, initial>{}, deps, subs);
do {
while (process_internal_events(anonymous{}, deps, subs)) {
}
process_defer_events(deps, subs, true, aux::type<defer_queue_t<initial>>{}, events_t{});
} while (process_queued_events(deps, subs, aux::type<process_queue_t<initial>>{}, events_t{}) ||
process_internal_events(anonymous{}, deps, subs));
process_event(on_entry<_, initial>{}, deps, subs);
}

template <class TEvent, class TDeps, class TSubs, class... Ts,
Expand Down Expand Up @@ -217,15 +204,15 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
const auto lock = thread_safety_.create_lock();
(void)lock;

auto handled = false;
#if defined(__cpp_fold_expressions) // __pph__
return ((dispatch_t::template dispatch<0, TMappings>(*this, current_state_[Ns], event, deps, subs, states)), ...);
((handled |= dispatch_t::template dispatch<0, TMappings>(*this, current_state_[Ns], event, deps, subs, states)), ...);
#else // __pph__
auto handled = false;
(void)aux::swallow{
0,
(handled |= dispatch_t::template dispatch<0, TMappings>(*this, current_state_[Ns], event, deps, subs, states), 0)...};
return handled;
#endif // __pph__
return handled;
}

template <class TMappings, class TEvent, class TDeps, class TSubs, class... TStates>
Expand Down Expand Up @@ -290,15 +277,11 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
template <class TDeps, class TSubs, class TEvent>
bool process_event_no_defer(TDeps &deps, TSubs &subs, const void *data) {
const auto &event = *static_cast<const TEvent *>(data);
policies::log_process_event<sm_t>(aux::type<logger_t>{}, deps, event);
#if BOOST_SML_DISABLE_EXCEPTIONS // __pph__
const auto handled = process_event_impl<get_event_mapping_t<TEvent, mappings>>(event, deps, subs, states_t{},
aux::make_index_sequence<regions>{});
#else // __pph__
const auto handled = process_event_noexcept<get_event_mapping_t<TEvent, mappings>>(event, deps, subs, has_exceptions{});
#endif // __pph__
bool handled = process_internal_events(event, deps, subs);

if (handled && defer_again_) {
++defer_it_;
return false;
} else {
defer_.erase(defer_it_);
defer_it_ = defer_.begin();
Expand All @@ -319,9 +302,8 @@ struct sm_impl : aux::conditional_t<aux::is_empty<typename TSM::sm>::value, aux:
defer_again_ = false;
defer_it_ = defer_.begin();
defer_end_ = defer_.end();
processed_events = defer_it_ != defer_end_;
while (defer_it_ != defer_end_) {
(this->*dispatch_table[defer_it_->id])(deps, subs, defer_it_->data);
processed_events |= (this->*dispatch_table[defer_it_->id])(deps, subs, defer_it_->data);
defer_again_ = false;
}
defer_processing_ = false;
Expand Down
31 changes: 18 additions & 13 deletions include/boost/sml/back/transitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,8 @@ template <class T>
struct transitions<T> {
template <class TEvent, class SM, class TDeps, class TSubs>
static bool execute(const TEvent& event, SM& sm, TDeps& deps, TSubs& subs, typename SM::state_t& current_state) {
return execute_impl(event, sm, deps, subs, current_state);
}

template <class TEvent, class SM, class TDeps, class TSubs>
static bool execute_impl(const TEvent& event, SM& sm, TDeps& deps, TSubs& subs, typename SM::state_t& current_state) {
return aux::get<T>(sm.transitions_).execute(event, sm, deps, subs, current_state, typename SM::has_entry_exits{});
}

template <class _, class TEvent, class SM, class TDeps, class TSubs>
static bool execute_impl(const on_exit<_, TEvent>& event, SM& sm, TDeps& deps, TSubs& subs,
typename SM::state_t& current_state) {
aux::get<T>(sm.transitions_).execute(event, sm, deps, subs, current_state, typename SM::has_entry_exits{});
return false; // from bottom to top
}
};

template <>
Expand All @@ -72,6 +60,7 @@ struct transitions<aux::false_type> {
}
};

/// @brief Event executor on a sub state machine with transition in parent state machine.
template <class TSM, class T, class... Ts>
struct transitions_sub<sm<TSM>, T, Ts...> {
template <class TEvent, class SM, class TDeps, class TSubs>
Expand Down Expand Up @@ -101,13 +90,29 @@ struct transitions_sub<sm<TSM>, T, Ts...> {
sub_sm<sm_impl<TSM>>::get(&subs).process_event(event, deps, subs);
return true; // from top to bottom
}

template <class _, class TEvent, class SM, class TDeps, class TSubs>
static bool execute_impl(const back::on_exit<_, TEvent>& event, SM& sm, TDeps& deps, TSubs& subs,
typename SM::state_t& current_state) {
sub_sm<sm_impl<TSM>>::get(&subs).process_event(event, deps, subs);
transitions<T, Ts...>::execute(event, sm, deps, subs, current_state);
return true; // from bottom to top
}
};

/// @brief Event executor on a sub state machine without transition in parent state machine.
template <class TSM>
struct transitions_sub<sm<TSM>> {
template <class TEvent, class SM, class TDeps, class TSubs>
static bool execute(const TEvent& event, SM&, TDeps& deps, TSubs& subs, typename SM::state_t&) {
return sub_sm<sm_impl<TSM>>::get(&subs).template process_event<TEvent>(event, deps, subs);
return sub_sm<sm_impl<TSM>>::get(&subs).process_event(event, deps, subs);
}

template <class, class SM, class TDeps, class TSubs>
static bool execute(const anonymous&, SM&, TDeps&, TSubs&, typename SM::state_t&) {
// Do not propagate anonymous events to sub state machine
// Anonymous events will be generated inside sub-statemachine by initial process_event.
return false;
}
};

Expand Down
Loading