[MSM] event deferral and dispatching with base event

Hi Christophe I'm running the attached test program it generates the following output : entering: Idle MS1_ leaving: Idle Action: MS1::onEvent1 entering: RunningStateMachine MS1_ entering: RunningStateMachine::PseudoEntry1 leaving: RunningStateMachine::PseudoEntry1 entering: Inner1 RunningStateMachine_ entering: InnerState11 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 I believe it is incorrect after state machine entered state InnerState11 . FwdGuard should have been called ones with event5 and than 3 times with event1 and event1 shall have triggered after the first dispatching a no transaction. But this case no trans was triggers on even1 and and the deferred event5 got dispatched even there was no state change for every event1 dispatching. this breaks our code execution completely :(. Br. Richard

I'm running the attached test program it generates the following output :
entering: Idle MS1_ leaving: Idle Action: MS1::onEvent1 entering: RunningStateMachine MS1_ entering: RunningStateMachine::PseudoEntry1 leaving: RunningStateMachine::PseudoEntry1 entering: Inner1 RunningStateMachine_ entering: InnerState11 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5
Hi Richard, unfortunately, I don't have good news. We are using non-standard, self-made UML features (base event, Defer functor) here so we're moving in uncharted territory.
I believe it is incorrect after state machine entered state InnerState11 . FwdGuard should have been called ones with event5 and than 3 times with event1 and event1 shall have triggered after the first dispatching a no transaction. But this case no trans was triggers on even1 and and the deferred event5 got dispatched even there was no state change for every event1 dispatching.
After thinking about it, I think I will disagree. What you could expect at first would be one call with event5, then with event1, then event5, then event1, then event5 etc. Why? Because we have a transition conflict between the transition: Row < Inner1 , baseEvent , none , ProcessBaseEvent , FwdGuard
and Row < RunningStateMachine, event5 , none , Defer, none > If you follow the other discussion on this list, there is talk about priority. The Standard says that the most inner transitions have higher priority, so when you want to process event5, the above transition gets tried first and rejects event5. So the transition did not fire. Again, as the Standard says, we continue until one fires. We then try the second one, which has no guard, so it fires and defers the event5. Then comes event1, the above transition rejects, processing of event1 stops here. We try again the deferrd event5, and you see it again. And again it is deferred. And again and again. So, what you COULD expect would be: FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 But there is a second factor here, a conflict between an event (event1) and its base state. I can only advise you to avoid this. I see this as the fsm equivalent of Meyer's tip "make base classes abstract". In our case, we get rows added by msm in your SM1 transition table for events present in RunningStateMachine's table: RunningStateMachine: event1 (comes from _row < PseudoEntry1 , event1 , Inner1 >) RunningStateMachine: baseEvent (comes from Row < Inner1 , baseEvent , none , ProcessBaseEvent , FwdGuard >) This means event1 is in conflict with his base class. MSM tries both transitions, with event1 and baseEvent, as with any conflict. Interestingly, both map to the one from baseEvent, so it is called twice, which gives you what you see. So, what should msm do? Remove the transition with eventBase? No because base events would not work for submachines any more. Remove the transition with event1 because eventBase is present? Also no, because you would only get the submachine called with baseEvent (would be slicing, again, see Meyer). So, I need to think about it, but I really see no way to make this work :(
this breaks our code execution completely :(.
I understand it's bad. All I can suggest you is: - do not create conflicts between an event and its base. I don't see how this could be a right design. - if you don't want event5 to come haunt you forever, stick to the UML conform deferring inside a state unless you really know you will get no transition conflict. Sorry, not to be able to help more. Regards, Christophe

On 19 July 2011 23:16, Christophe Henry <christophe.j.henry@googlemail.com> wrote:
I'm running the attached test program it generates the following output :
entering: Idle MS1_ leaving: Idle Action: MS1::onEvent1 entering: RunningStateMachine MS1_ entering: RunningStateMachine::PseudoEntry1 leaving: RunningStateMachine::PseudoEntry1 entering: Inner1 RunningStateMachine_ entering: InnerState11 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5
Hi Richard,
unfortunately, I don't have good news. We are using non-standard, self-made UML features (base event, Defer functor) here so we're moving in uncharted territory.
I believe it is incorrect after state machine entered state InnerState11 . FwdGuard should have been called ones with event5 and than 3 times with event1 and event1 shall have triggered after the first dispatching a no transaction. But this case no trans was triggers on even1 and and the deferred event5 got dispatched even there was no state change for every event1 dispatching.
After thinking about it, I think I will disagree. What you could expect at first would be one call with event5, then with event1, then event5, then event1, then event5 etc. Why? Because we have a transition conflict between the transition: Row < Inner1 , baseEvent , none , ProcessBaseEvent , FwdGuard > and Row < RunningStateMachine, event5 , none , Defer, none >
If you follow the other discussion on this list, there is talk about priority. The Standard says that the most inner transitions have higher priority, so when you want to process event5, the above transition gets tried first and rejects event5. So the transition did not fire. Again, as the Standard says, we continue until one fires. We then try the second one, which has no guard, so it fires and defers the event5.
Then comes event1, the above transition rejects, processing of event1 stops here. We try again the deferrd event5, and you see it again. And again it is deferred. And again and again. So, what you COULD expect would be: FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1
But there is a second factor here, a conflict between an event (event1) and its base state. I can only advise you to avoid this. I see this as the fsm equivalent of Meyer's tip "make base classes abstract". In our case, we get rows added by msm in your SM1 transition table for events present in RunningStateMachine's table: RunningStateMachine: event1 (comes from _row < PseudoEntry1 , event1 , Inner1 >) RunningStateMachine: baseEvent (comes from Row < Inner1 , baseEvent , none , ProcessBaseEvent , FwdGuard >)
This means event1 is in conflict with his base class. MSM tries both transitions, with event1 and baseEvent, as with any conflict. Interestingly, both map to the one from baseEvent, so it is called twice, which gives you what you see.
So, what should msm do? Remove the transition with eventBase? No because base events would not work for submachines any more. Remove the transition with event1 because eventBase is present? Also no, because you would only get the submachine called with baseEvent (would be slicing, again, see Meyer).
So, I need to think about it, but I really see no way to make this work :(
this breaks our code execution completely :(.
I understand it's bad. All I can suggest you is: - do not create conflicts between an event and its base. I don't see how this could be a right design. - if you don't want event5 to come haunt you forever, stick to the UML conform deferring inside a state unless you really know you will get no transition conflict.
Ok if I use UML like definition for the event deferral than at least event 5 is not getting dispatched each time thanks for that. And actually I can leave with the situation that even1 is dispatched 2 times it only happens when no trans is taken in sub state machine so than it is not hurting. What I find disturbing that in this case the No Trans in not getting called ? Is it possible to fix at least this ?.
Sorry, not to be able to help more.
No problem you are a great help to us !.
Regards,
Christophe
Cheers Richard
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

<snip>
I understand it's bad. All I can suggest you is: - do not create conflicts between an event and its base. I don't see how this could be a right design. - if you don't want event5 to come haunt you forever, stick to the UML conform deferring inside a state unless you really know you will get no transition conflict.
Ok if I use UML like definition for the event deferral than at least event 5 is not getting dispatched each time thanks for that. And actually I can leave with the situation that even1 is dispatched 2 times it only happens when no trans is taken in sub state machine so than it is not hurting. What I find disturbing that in this case the No Trans in not getting called ? Is it possible to fix at least this ?.
That no_transition is not called is actually normal as it's supposed to be an error, or at least a warning. The no_transition handler is never called on a submachine. Why? Because someone else might handle the event. To handle an event, msm follows the UML rule of "deeper first", so Inner1 gets first a chance to handle the event. If it doesn't, RunningStateMachine is tried. If it doesn't, SM1, and if it doesn't, then we get no_transition on SM1. An event is considered handled if a transition fires OR if a guard rejected it. no_transition only means "hey you made a programming error, nobody had even a chance to handle this". But you have a transition which handles event1 because of your baseEvent catch-all transition. Of course we are only a compile-time flag away from changing this but I don't think you'll be happy with getting tons of no_transition calls in Inner1 and RunningStateMachine for every event which was thought for SM1. The real issue is actually the double call. I need to think about it more, maybe there is a way for msm to handle this, I just didn't find it out yet. Regards, Christophe

Richard Szabo wrote:
I'm running the attached test program it generates the following output :
entering: Idle MS1_ leaving: Idle Action: MS1::onEvent1 entering: RunningStateMachine MS1_ entering: RunningStateMachine::PseudoEntry1 leaving: RunningStateMachine::PseudoEntry1 entering: Inner1 RunningStateMachine_ entering: InnerState11 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event1 FwdGuard: returns:0, event: event5
Ok if I use UML like definition for the event deferral than at least event 5 is not getting dispatched each time thanks for that. And actually I can leave with the situation that even1 is dispatched 2 times it only happens when no trans is taken in sub state machine so than it is not hurting.
Hi Richard, I unfortunately didn't manage to find a solution before my vacations, but I now had more time and found a way around the multiple event1 dispatches. You can get it from trunk (rev. 74109). This, combined with your event5 deferring the UML way, will now get you the expected behaviour. HTH, Christophe
participants (2)
-
Christophe Henry
-
Richard Szabo