Index: boost/msm/back/state_machine.hpp =================================================================== --- boost/msm/back/state_machine.hpp (revision 78744) +++ boost/msm/back/state_machine.hpp (working copy) @@ -2526,9 +2526,12 @@ // given region starts with the entry pseudo state as active state self->m_states[find_region_id::region_index] = state_id; self->internal_start(evt.m_event); - // and we process the transition in the zone of the newly active state - // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside - self->process_event(evt.m_event); + if (self->m_events_queue.m_events_queue.empty()) + { + // and we process the transition in the zone of the newly active state + // (entry pseudo states are, according to UML, a state connecting 1 transition outside to 1 inside + self->process_event(evt.m_event); + } } private: // helper for the fork case, does almost like the direct entry Index: libs/msm/test/Jamfile.v2 =================================================================== --- libs/msm/test/Jamfile.v2 (revision 78744) +++ libs/msm/test/Jamfile.v2 (working copy) @@ -34,6 +34,7 @@ [ run OrthogonalDeferred.cpp ] [ run OrthogonalDeferred2.cpp ] [ run OrthogonalDeferredEuml.cpp ] + [ run PseudoEntry.cpp ] [ run SimpleEuml.cpp ] [ run SimpleEuml2.cpp ] [ run SimpleInternal.cpp ] Index: libs/msm/test/PseudoEntry.cpp =================================================================== --- libs/msm/test/PseudoEntry.cpp (revision 0) +++ libs/msm/test/PseudoEntry.cpp (working copy) @@ -0,0 +1,254 @@ +// Copyright 2012 Christophe Henry, Takatoshi Kondo +// henry UNDERSCORE christophe AT hotmail DOT com, redboltz AT gmail DOT com +// This is an extended version of the state machine available in the boost::mpl library +// Distributed under the same license as the original. +// Copyright for the original version: +// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed +// under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +// back-end +#include +//front-end +#include +#include + +#define BOOST_TEST_MODULE MyTest +#include + +namespace msm = boost::msm; +namespace mpl = boost::mpl; +using namespace boost::msm::front; + +namespace +{ + // events + struct event1 {}; + struct event2 {}; + + // front-end: define the FSM structure + struct L0Fsm_ : public state_machine_def + { + // The list of FSM states + struct L1State1 : public state<> + { + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + }; + struct L1Fsm_ : public state_machine_def + { + unsigned int entry_action_counter; + + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + + // test with a pseudo entry + struct L2PseudoEntry : public msm::front::entry_pseudo_state<0> + { + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + }; + struct L2Fsm_ : public state_machine_def + { + unsigned int entry_action_counter; + unsigned int deferred_action_counter; + + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + + // test with a pseudo entry + struct L3PseudoEntry : public entry_pseudo_state<0> + { + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + }; + struct L3State1 : public state<> + { + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + }; + struct L3State2 : public state<> + { + template + void on_entry(Event const&,FSM& ) {++entry_counter;} + template + void on_exit(Event const&,FSM& ) {++exit_counter;} + int entry_counter; + int exit_counter; + }; + + struct EntryAction { + template + void operator()(Event const&, Fsm& f, SourceState&, TargetState&) { + ++f.entry_action_counter; + } + }; + struct DeferredAction { + template + void operator()(Event const&, Fsm& f, SourceState&, TargetState&) { + ++f.deferred_action_counter; + } + }; + + // the initial state. Must be defined + typedef L3State1 initial_state; + + // Transition table for SubSubFsm2 + struct transition_table : mpl::vector< + // Start Event Next Action Guard + // +---------------+--------+----------+----------------+-------+ + Row < L3PseudoEntry , none , L3State1 , EntryAction , none >, + Row < L3State1 , none , L3State2 , none , none >, + Row < L3State2 , event2 , none , DeferredAction , none > + // +---------------+--------+----------+----------------+-------+ + > {}; + + // Replaces the default no-transition response. + template + void no_transition(Event const& e, FSM&,int state) + { + BOOST_FAIL("no_transition called!"); + } + }; + typedef msm::back::state_machine L2Fsm; + + struct EntryAction { + template + void operator()(Event const&, Fsm& f, SourceState&, TargetState&) { + ++f.entry_action_counter; + } + }; + + // the initial state. Must be defined + typedef L2Fsm_ initial_state; + + // Transition table for SubFsm2 + struct transition_table : mpl::vector< + // Start Event Next Action Guard + // +---------------+-------+-------------------------+-------------+-------+ + Row < L2PseudoEntry , none , L2Fsm::entry_pt + , EntryAction , none > + // +---------------+-------+-------------------------+-------------+-------+ + > {}; + + // Replaces the default no-transition response. + template + void no_transition(Event const& e, FSM&,int state) + { + BOOST_FAIL("no_transition called!"); + } + }; + typedef msm::back::state_machine L1Fsm; + + // the initial state of the player SM. Must be defined + typedef L1State1 initial_state; + + // Enable deferred capability + typedef int activate_deferred_events; + + // transition actions + // guard conditions + + // Transition table for Fsm + struct transition_table : mpl::vector< + // Start Event Next Action Guard + // +----------+--------+-------------------------+--------+-------+ + Row < L1State1 , event1 , L1Fsm::entry_pt + , none , none >, + Row < L1State1 , event2 , none , Defer , none > + // +----------+--------+-------------------------+--------+-------+ + > {}; + + // Replaces the default no-transition response. + template + void no_transition(Event const& e, FSM&,int state) + { + BOOST_FAIL("no_transition called!"); + } + + // init counters + template + void on_entry(Event const&,FSM& fsm) + { + fsm.template get_state().entry_counter=0; + fsm.template get_state().exit_counter=0; + fsm.template get_state().entry_counter=0; + fsm.template get_state().exit_counter=0; + fsm.template get_state().entry_action_counter=0; + fsm.template get_state().template get_state().entry_counter=0; + fsm.template get_state().template get_state().exit_counter=0; + fsm.template get_state().template get_state().entry_action_counter=0; + fsm.template get_state().template get_state().deferred_action_counter=0; + fsm.template get_state().template get_state().entry_counter=0; + fsm.template get_state().template get_state().exit_counter=0; + fsm.template get_state().template get_state().template get_state().entry_counter=0; + fsm.template get_state().template get_state().template get_state().exit_counter=0; + fsm.template get_state().template get_state().template get_state().entry_counter=0; + fsm.template get_state().template get_state().template get_state().exit_counter=0; + fsm.template get_state().template get_state().template get_state().entry_counter=0; + fsm.template get_state().template get_state().template get_state().exit_counter=0; + + } + }; + typedef msm::back::state_machine L0Fsm; + + + BOOST_AUTO_TEST_CASE( my_test ) + { + L0Fsm p; + + p.start(); + BOOST_CHECK_MESSAGE(p.get_state().entry_counter == 1,"L1State1 entry not called correctly"); + BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"L1State1 should be active"); + + p.process_event(event2()); // Deferred + BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"L1State1 should be active"); + BOOST_CHECK_MESSAGE(p.get_state().entry_counter == 1,"L1State1 entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().exit_counter == 0,"L1State1 exit not called correctly"); + + p.process_event(event1()); + BOOST_CHECK_MESSAGE(p.current_state()[0] == 1,"L1Fsm should be active"); + BOOST_CHECK_MESSAGE(p.get_state().exit_counter == 1,"L1State1 exit not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().entry_counter == 1,"L1Fsm entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().entry_action_counter == 1,"L1Fsm entry action not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().entry_counter == 1,"L2EntryPoint entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().exit_counter == 1,"L2EntryPoint exit not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().entry_counter == 1,"L2Fsm entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().entry_action_counter == 1,"L2Fsm entry action not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().exit_counter == 0,"L2Fsm exit not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().get_state().entry_counter == 1,"L3PseudoEntry entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().get_state().exit_counter == 1,"L3PseudoEntry exit not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().get_state().entry_counter == 1,"L3State1 entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().get_state().exit_counter == 1,"L3State1 exit not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().get_state().entry_counter == 1,"L3State2 entry not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().get_state().exit_counter == 0,"L3State2 exit not called correctly"); + BOOST_CHECK_MESSAGE(p.get_state().get_state().deferred_action_counter == 1,"L2Fsm deferred action not called correctly"); + } +} +