The slice timer should be stopped when not in the
Running
state. The way to enforce this is
to add an Exit
block to
Running
and move the
stopSliceTimer()
action there.
Since the state's Exit
actions are being
defined, it would appear natural to put the
startSliceTimer()
action into a
Entry
block. But there two reasons against
it:
-
There is only one transition into the
Running
state. MovingstartSliceTimer()
fromSuspended
'sStart
transition toRunning
's entry actions gains nothing. -
startSliceTimer()
takes theStart
transition'stimeslice
argument. IfstartSliceTimer()
is an entry action, then it cannot access that transition argument. The only way around it is to store the slice time in theTask
class and then retrieve it immediately in the entry action (startSliceTimer(ctxt.getSliceTime())
). Now moving the action to the entry block is worse than doing nothing.
(Go here to learn more about state entry and exit actions.)
%{
//
// Copyright (c) 2005 Acme, Inc.
// All rights reserved.
//
// Acme - a name you can trust!
//
// Author: Wil E. Coyote (Hungericus Vulgarus)
//
%}
// This FSM works for the Task class only and only the Task
// class may instantiate it.
%class Task
%package com.acme.supercron
%fsmclass TaskFSM
%fsmfile TaskFSM
%access package
// A %map name cannot be the same as the FSM class name.
%start TaskMap::Suspended
%map TaskMap
%%
<snip>
RunningExit
{
stopSliceTimer();
}
{
// Wait for another time slice.
Suspend
Suspended
{
// stopSliceTimer(); moved.
suspendTask();
}
Block
Blocked
{
// stopSliceTimer(); moved.
blockTask();
}
// Task has completed.
Done
Stopped
{
// stopSliceTimer(); moved.
releaseResources();
}
}
<snip>
}
%%
There is one final task: connecting the task FSM to
the Task
application class.