$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r77840 - trunk/boost/msm/back
From: christophe.j.henry_at_[hidden]
Date: 2012-04-08 16:16:35
Author: chenry
Date: 2012-04-08 16:16:34 EDT (Sun, 08 Apr 2012)
New Revision: 77840
URL: http://svn.boost.org/trac/boost/changeset/77840
Log:
fix (no_transition not called for submachine objects on which process_event is directly called)
Text files modified: 
   trunk/boost/msm/back/state_machine.hpp |   113 +++++++++++++++++++++------------------ 
   1 files changed, 61 insertions(+), 52 deletions(-)
Modified: trunk/boost/msm/back/state_machine.hpp
==============================================================================
--- trunk/boost/msm/back/state_machine.hpp	(original)
+++ trunk/boost/msm/back/state_machine.hpp	2012-04-08 16:16:34 EDT (Sun, 08 Apr 2012)
@@ -1013,10 +1013,11 @@
         // Take the transition action and return the next state.
         static HandledEnum execute(library_sm& fsm, int region_index, int , transition_event const& evt)
         {
-             execute_return res = 
-                (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list)).process_event(evt); 
-             fsm.m_states[region_index]=get_state_id<stt,T1>::type::value;
-             return res;
+            // false as second parameter because this event is forwarded from outer fsm
+            execute_return res = 
+                (::boost::fusion::at_key<current_state_type>(fsm.m_substate_list)).process_event_internal(evt,false); 
+            fsm.m_states[region_index]=get_state_id<stt,T1>::type::value;
+            return res;
         }
         // helper metafunctions used by dispatch table and give the frow a new event
         // (used to avoid double entries in a table because of base events)
@@ -1249,50 +1250,11 @@
         do_exit(finalEvent,*this);
     }
 
-    // Main function used by clients of the derived FSM to make
-    // transitions. Can also be called for internally (for example in an action method) generated events.
+    // Main function used by clients of the derived FSM to make transitions.
     template<class Event>
     execute_return process_event(Event const& evt)
     {
-        HandledEnum ret_handled=HANDLED_FALSE;
-        // if the state machine has terminate or interrupt flags, check them, otherwise skip
-        if (is_event_handling_blocked_helper<Event>
-                ( ::boost::mpl::bool_<has_fsm_blocking_states<library_sm>::type::value>() ) )
-            return HANDLED_TRUE;
-        // if a message queue is needed and processing is on the way
-        if (!do_pre_msg_queue_helper<Event>
-                (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()) )
-        {
-            // wait for the end of current processing
-            return HANDLED_TRUE;
-        }
-        else
-        {
-            // prepare the next deferred event for handling
-            // if one defer is found in the SM, otherwise skip
-            handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
-            defer_helper.do_pre_handle_deferred();
-            // process event
-            HandledEnum handled = this->do_process_helper<Event>
-                (evt,::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>());
-            if (handled)
-            {
-                ret_handled = handled;
-            }
-
-            // process completion transitions BEFORE any other event in the pool (UML Standard 2.3 §15.3.14)
-            handle_eventless_transitions_helper<library_sm> eventless_helper(this,(handled == HANDLED_TRUE));
-            eventless_helper.process_completion_event();
-
-            // after handling, take care of the deferred events
-            defer_helper.do_post_handle_deferred(handled);
-
-            // now check if some events were generated in a transition and was not handled
-            // because of another processing, and if yes, start handling them
-            do_post_msg_queue_helper(::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
-
-            return ret_handled;
-        }       
+        return process_event_internal(evt,true);
     }
 
     template <class EventType>
@@ -1765,16 +1727,16 @@
     }
     // the following 2 functions handle the processing either with a try/catch protection or without
     template <class StateType,class EventType>
-    HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &)
+    HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::true_ const &, bool is_direct_call)
     {
-        return this->do_process_event(evt);
+        return this->do_process_event(evt,is_direct_call);
     }
     template <class StateType,class EventType>
-    HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &)
+    HandledEnum do_process_helper(EventType const& evt, ::boost::mpl::false_ const &, bool is_direct_call)
     {
         try
         {
-            return this->do_process_event(evt);
+            return this->do_process_event(evt,is_direct_call);
         }
         catch (std::exception& e)
         {
@@ -1978,9 +1940,55 @@
         HandledEnum&    result;
     };
 
+    // Main function used internally to make transitions
+    // Can only be called for internally (for example in an action method) generated events.
+    template<class Event>
+    execute_return process_event_internal(Event const& evt, bool is_direct_call)
+    {
+        HandledEnum ret_handled=HANDLED_FALSE;
+        // if the state machine has terminate or interrupt flags, check them, otherwise skip
+        if (is_event_handling_blocked_helper<Event>
+                ( ::boost::mpl::bool_<has_fsm_blocking_states<library_sm>::type::value>() ) )
+            return HANDLED_TRUE;
+        // if a message queue is needed and processing is on the way
+        if (!do_pre_msg_queue_helper<Event>
+                (evt,::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>()) )
+        {
+            // wait for the end of current processing
+            return HANDLED_TRUE;
+        }
+        else
+        {
+            // prepare the next deferred event for handling
+            // if one defer is found in the SM, otherwise skip
+            handle_defer_helper<library_sm> defer_helper(m_deferred_events_queue);
+            defer_helper.do_pre_handle_deferred();
+            // process event
+            HandledEnum handled = this->do_process_helper<Event>
+                (evt,::boost::mpl::bool_<is_no_exception_thrown<library_sm>::type::value>(),is_direct_call);
+            if (handled)
+            {
+                ret_handled = handled;
+            }
+
+            // process completion transitions BEFORE any other event in the pool (UML Standard 2.3 §15.3.14)
+            handle_eventless_transitions_helper<library_sm> eventless_helper(this,(handled == HANDLED_TRUE));
+            eventless_helper.process_completion_event();
+
+            // after handling, take care of the deferred events
+            defer_helper.do_post_handle_deferred(handled);
+
+            // now check if some events were generated in a transition and was not handled
+            // because of another processing, and if yes, start handling them
+            do_post_msg_queue_helper(::boost::mpl::bool_<is_no_message_queue<library_sm>::type::value>());
+
+            return ret_handled;
+        }       
+    }
+
     // minimum event processing without exceptions, queues, etc.
     template<class Event>
-    HandledEnum do_process_event(Event const& evt)
+    HandledEnum do_process_event(Event const& evt, bool is_direct_call)
     {
         HandledEnum handled = HANDLED_FALSE;
         // dispatch the event to every region
@@ -1990,9 +1998,10 @@
         // if the event has not been handled and we have orthogonal zones, then
         // generate an error on every active state 
         // for state machine states contained in other state machines, do not handle
-        // but let the containing sm handle the error
+        // but let the containing sm handle the error, unless the event was generated in this fsm 
+        // (by calling process_event on this fsm object, is_direct_call == true)
         // completion events do not produce an error
-        if (!handled && !is_contained() && !is_completion_event<Event>::type::value)
+        if ( (!is_contained() || is_direct_call) && !handled && !is_completion_event<Event>::type::value)
         {
             for (int i=0; i<nr_regions::value;++i)
             {