Skip to content

fix: back::process<E> from sub-SM now routes to root SM queue (issue #400)#687

Merged
kris-jusiak merged 2 commits into
boost-ext:masterfrom
PavelGuzenfeld:fix/issue-400-back-process-root-queue
May 27, 2026
Merged

fix: back::process<E> from sub-SM now routes to root SM queue (issue #400)#687
kris-jusiak merged 2 commits into
boost-ext:masterfrom
PavelGuzenfeld:fix/issue-400-back-process-root-queue

Conversation

@PavelGuzenfeld
Copy link
Copy Markdown
Contributor

@PavelGuzenfeld PavelGuzenfeld commented May 27, 2026

Problem

When an action inside a sub-SM calls back::process<E> to enqueue an event, the event is pushed to the sub-SM's own process_ queue instead of the root SM's. The root SM's drain loop never empties sub-SM queues, so those events are silently dropped.

Minimal reproducer:

struct sub {
  auto operator()() const noexcept {
    using namespace sml;
    return make_transition_table(
      * s1 + event<e1> / [](back::process<e2> proc) { proc(e2{}); }
    );
  }
};
struct root {
  std::string received;
  auto operator()() noexcept {
    using namespace sml;
    return make_transition_table(
      * state<sub> + event<e2> / [this] { received += "e2|"; }
    );
  }
};

sml::sm<root, sml::process_queue<std::queue>> sm;
sm.process_event(e1{});
// Before fix: received == ""    (e2 silently dropped)
// After fix:  received == "e2|"

Originally reported in #400 and #562 (with a fix sketch by rhaschke).

Root cause

The 4-parameter get_arg overload for back::process<TEvents...> receives the current SM (Tsm &sm) and binds back::process to sm.process_. When executing a sub-SM action, sm is the sub-SM — not the root. The 6-param dispatch falls through the variadic ... fallback which calls the 4-param version, so the wrong queue is used.

Compare with front::actions::process (the inline sml::process(event) syntax), which has always correctly used:

aux::get<get_root_sm_t<TSubs>>(subs).process_.push(event);

Fix

Add a 6-parameter get_arg overload for back::process<TEvents...> (preferred over the ... fallback via the int/... trick) that binds back::process to the root SM's queue:

template <class... TEvents, class TEvent, class Tsm, class TDeps, class TSubs>
constexpr decltype(auto) get_arg(
    const aux::type_wrapper<back::process<TEvents...>> &,
    const TEvent &, Tsm &, TDeps &, TSubs &subs, int) {
  return back::process<TEvents...>{
      aux::get<get_root_sm_t<TSubs>>(subs).process_};
}

For non-nested SMs get_root_sm_t<TSubs> returns the root itself — no behaviour change for flat state machines.

Verification

  • GCC C++17 and C++20: all tests pass
  • MSVC 19.51.36244 (VS 2022 17.x) C++20: 33/33 pass
  • MSVC C++17: 30/33 pass (same 3 pre-existing C4458 upstream failures)

PavelGuzenfeld and others added 2 commits May 27, 2026 08:26
…oost-ext#400)

Events pushed via back::process<TEvents...> from an action inside a sub-SM
were queued in the sub-SM's own process_ queue instead of the root SM's.
The root SM's drain loop never empties the sub-SM's queue, so those events
were silently dropped after the inner dispatch returned.

Root cause: the 4-parameter get_arg overload for back::process<TEvents...>
received the sub-SM instance (Tsm &sm) and used sm.process_.  The TSubs
pool is available as a 6th argument in the call::execute path but the
specific overload for back::process didn't use it.

Fix: add a 6-parameter get_arg overload (preferred over the variadic
fallback via the int/... trick) that retrieves the root SM via
get_root_sm_t<TSubs> and binds back::process to its process_ queue.
This matches the behaviour of front::actions::process (the sml::process(e)
inline-action syntax), which already used get_root_sm_t correctly.

Non-nested SMs are unaffected: in that case get_root_sm_t<TSubs> returns
the root itself, so the queue is the same as before.

Test: back_process_from_sub_sm_routes_to_root_queue in actions_process.cpp
Verified: GCC C++17/C++20 (all pass), MSVC 19.51.36244 C++20 (33/33 pass)
@kris-jusiak kris-jusiak merged commit ddcbb55 into boost-ext:master May 27, 2026
5 checks passed
@PavelGuzenfeld PavelGuzenfeld deleted the fix/issue-400-back-process-root-queue branch May 27, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants