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
Runningstate. MovingstartSliceTimer()fromSuspended'sStarttransition toRunning's entry actions gains nothing. -
startSliceTimer()takes theStarttransition'stimesliceargument. IfstartSliceTimer()is an entry action, then it cannot access that transition argument. The only way around it is to store the slice time in theTaskclass 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.