Boost C++ Libraries of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Chapter 6. Internals

Table of Contents

Backend: Run To Completion
Frontend / Backend interface
Generated state ids
Metaprogramming tools

This chapter describes the internal machinery of the back-end, which can be useful for UML experts but can be safely ignored for most users. For implementers, the interface between front- and back- end is also described in detail.

Backend: Run To Completion

The back-end implements the following run-to completion algorithm:

  • Check if one region of the concrete state machine is in a terminate or interrupt state. If yes, event processing is disabled while the condition lasts (forever for a terminate pseudo-state, while active for an interrupt pseudo-state).

  • If the message queue feature is enabled and if the state machine is already processing an event, push the currently processed event into the queue and end processing. Otherwise, remember that the state machine is now processing an event and continue.

  • If the state machine detected that no deferred event is used, skip this step. Otherwise, mark the first deferred event from the deferred queue as active.

  • Now start the core of event dispatching. If exception handling is activated, this will happen inside a try/catch block and the front-end exception_caught is called if an exception occurs.

  • The event is now dispatched in turn to every region, in the order defined by the initial state front-end definition. This will, for every region, call the corresponding front-end transition definition (the "row" or "Row" of the transition table).

  • Without transition conflict, if for a given region a transition is possible, the guard condition is checked. If it returns true, the transition processing continues and the current state's exit action is called, followed by the transition action behavior and the new active state's entry behavior.

  • With transition conflicts (several possible transitions, disambiguated by mutually exclusive guard conditions), the guard conditions are tried in reverse order of their transition definition in the transition table. The first one returning true selects its transition. Note that this is not defined by the UML standard, which simply specifies that if the guard conditions are not mutually exclusive, the state machine is ill-formed and the behaviour undefined. Relying on this implementation-specific behaviour will make it harder for the developer to support another state machine framework.

  • If at least one region processes the event, this event is seen as having been accepted. If not, the library calls no_transition on the state machine for every contained region.

  • If the currently active state is a submachine, the behaviour is slightly different. The UML standard specifies that internal transitions have to be tried first, so the event is first dispatched to the submachine. Only if the submachine does not accept the event are other (non internal) transitions tried.

  • This back-end supports simple states' and submachines' internal transitions. These are provided in the state's internal_transition_table type. Transitions defined in this table are added at the end of the main state machine's transition table, but with a lesser priority than the submachine's transitions (defined in transition_table). This means, for simple states, that these transitions have higher priority than non-internal transitions, conform to the UML standard which gives higher priority to deeper-level transitions. For submachines, this is a non-standard addition which can help make event processing faster by giving a chance to bypass subregion processing. With standard UML, one would need to add a subregion only to process these internal transitions, which would be slower.

  • After the dispatching itself, the deferred event marked in step 3 (if any) now gets a chance of processing.

  • Then, events queued in the message queue also get a dispatching chance

  • Finally, completion / anonymous transitions, if to be found in the transition table, also get their dispatching chance.

This algorithm illustrates how the back-end configures itself at compile-time as much as possible. Every feature not found in a given state machine definition is deactivated and has therefore no runtime cost. Completion events, deferred events, terminate states, dispatching to several regions, internal transitions are all deactivated if not used. User configuration is only for exception handling and message queue necessary.