Search topics...
State MachinesImplementation & Designintermediate

How do you handle events that arrive during a state transition?

0 upvotes
Practice with AISoon
Study the fundamentals first — State Machines topic page

This is the run-to-completion problem. The danger: an action inside a transition synchronously dispatches another event, which mutates state mid-transition. When the outer transition's state assignment runs, the inner update is lost — or worse, both updates conflict in undefined order.

c
static void on_button_in_idle(void) {
led_on();
fsm_handle_event(E_TIMER_EXPIRY); // re-entry — bug!
state = S_ACTIVE;
}

The standard discipline is run-to-completion: an event handler must finish entirely (actions executed, state updated) before the next event is dispatched. Two common ways to enforce it:

1. Event queue / message queue. The FSM task drains a queue, processing one event at a time:

c
while (1) {
xQueueReceive(event_q, &e, portMAX_DELAY);
fsm_handle_event(e);
/* loop back, get next event */
}

If an action needs to fire a follow-up event, it enqueues it (xQueueSend) rather than dispatching synchronously. The current event runs to completion; the follow-up gets processed cleanly on the next iteration. This is the canonical pattern in event-driven FSMs and is the basis for the active-object pattern.

2. Re-entry detection (less common). A boolean flag indicates whether dispatch is in progress; nested calls assert or buffer the event. Brittle and harder to reason about than queues; use only when you can't have a queue (extremely tight bare-metal).

In real-world embedded code, the queue-based pattern is overwhelmingly preferred. Most RTOS-based projects naturally arrive at it: each FSM is its own task with its own event queue (active object), and cross-FSM communication is queue posting. The pattern eliminates a whole class of subtle race bugs.

The interview-relevant lesson: name run-to-completion explicitly, identify synchronous re-entry as the failure mode, and propose the queue-based fix. Bonus points for mentioning that ISRs should also enqueue (using *FromISR API variants) rather than calling the FSM directly.

Source: State Machines Q&A