Boost logo

Boost :

Subject: Re: [boost] [msm] guard behavior if guard guards the transition MSM threats event as handled is that correct ?
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2011-11-23 15:49:30


Hi Richard,

> the attached example I think shows 2 problems.
>
> 1st is that the deferral of event3 is not happening.
> 2nd is that the no_transition function is never called.
>
> the output of the run is :
>
> MS1 Entering State: Idle by: event1
> MS1 Leaving State: Idle by: event1
> MS1 Entering State: SubRunning by: event1
> FwdGuard: returns:1, event: event2
> Processing BaseEvent Instance(event2)
> Setting guard false
> FwdGuard: returns:0, event: event3
> FwdGuard: returns:0, event: event4
> FwdGuard: returns:0, event: event5
> MS1 Leaving State: SubRunning by: event5
> MS1 Entering State: AfterSub by: event5
>
> I think it shall be :
>
> MS1 Entering State: Idle by: event1
> MS1 Leaving State: Idle by: event1
> MS1 Entering State: SubRunning by: event1
> FwdGuard: returns:1, event: event2
> Processing BaseEvent Instance(event2)
> Setting guard false
> FwdGuard: returns:0, event: event3
> FwdGuard: returns:0, event: event4
> MS1 no_transition event (event4)
> MS1 Leaving State: SubRunning by: event5
> MS1 Entering State: AfterSub by: event5
> MS1 no_transition event (event3)
>
>
> So in this example event3 and event4 are never triggered a transition ...
> the Row < SubRunning , baseEvent , none , ProcessBaseEvent ,
> FwdGuard
>> was guarded by the FwdGuard for these events.
>
> Is my expected behavior wrong ?

Well, hard to answer because the Standard does not discuss conflicts between
a state declaration and a transition, so your guess is as good as mine ;-)

Let's say that this is the intended behavior. In the current implementation,
the state declaration has the lowest priority. This means the transition
table comes first, and if it handles the event, then processing stops here
so your deferred declaration has no effect.

The answer to the question in your title is yes. If a guard rejects the
event, the event is really handled (rejection is a perfectly acceptable
event handling) so there is no call to no_transition, which is to be seen as
a catch-all error handler in case you forget to handle an event. Seeing that
the default version is an assert, imagine what you'd get at every guard
rejection ;-)

> If guard is executed but the transition actually is triggered because it
> is guarded out why this event treated as handled event ?.

Because a guard is not an error, a call to no_transition probably is.
I think the best way to solve the conflict between state declaration and the
transition table wanting to process is to state what you want in the
transition table itself:

Row < SubRunning , event3 , none , Defer , none /* or guard */ >

will do.

Well, there is a small bug, but not where you expect it. It seems that the
processing continues even though this transition defers the event. I just
fixed this in the trunk (rev. 75641).

> This 2 problems breaks my current nested state machine implementation
> because I'm using no_transition to forward the event to the outer state
> machine. I'm confused :(.

I think this will not work (and should not) because there is no call to
no_transition in a submachine (I don't see it here but I suppose your real
code is bigger). The reason is the same as above, no_transition is an error
and will assert. But if a submachine cannot process an event, it is not
necessarily an error, the outer machine should get its chance to process the
event. I'm also afraid you're trying to keep a pointer to the outer machine
to process the event (cycle). I suggest pushing the event to a pseudo exit,
which will achieve the same a better way.

HTH,
Christophe


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk