T2D/TGB Pausing and resuming schedules
by Gregory Stewart · 07/03/2006 (6:34 pm) · 0 comments
Download Code File
With some simple modifications to three files, namely simBase.h, simBase.cc, and simManager.cc, you can add support for pausing and resuming events that have been created with the schedule() command in TorqueScript.
How this works is simple. A few variables (along with a pause() and resume() function) are added to the SimEvent class that allow you to keep track of whether an event has been paused. If an event is paused, the schedule runs as normal but when it comes time to execute the code, if the event is paused, it simply gets re-added to the queue instead of executing the command. This basically keeps the scheduled event continously in the queue until it is unpaused (resumed). Paused events can be cancelled and queried like normal events.
There are three additional console functions that have been added to expose the functionality of pausing/resuming schedules:
Here is some sample code on how to use this in a script:
Below is a diff output of the differences between the original files and the new modified ones.
simBase.h
simBase.cc
simManager.cc
With some simple modifications to three files, namely simBase.h, simBase.cc, and simManager.cc, you can add support for pausing and resuming events that have been created with the schedule() command in TorqueScript.
How this works is simple. A few variables (along with a pause() and resume() function) are added to the SimEvent class that allow you to keep track of whether an event has been paused. If an event is paused, the schedule runs as normal but when it comes time to execute the code, if the event is paused, it simply gets re-added to the queue instead of executing the command. This basically keeps the scheduled event continously in the queue until it is unpaused (resumed). Paused events can be cancelled and queried like normal events.
There are three additional console functions that have been added to expose the functionality of pausing/resuming schedules:
pauseEvent( %scheduleId ); // pauses an event resumeEvent( %scheduleId ); // resumes an event isEventPaused( %scheduleId ); // checks to see if an event is paused
Here is some sample code on how to use this in a script:
$myId = schedule( 30000, 0, destroyTheWorld );
...
if ($somethingIsTrue)
{
pauseEvent( $myId );
}
...
resumeEvent( $myId );
// check to see if event is paused
if (isEventPaused( $myId )
{
// do something cool
}Below is a diff output of the differences between the original files and the new modified ones.
simBase.h
--- original_simBase.h 2006-03-06 08:16:26.000000000 -0600
+++ simBase.h 2006-04-22 19:58:37.679913600 -0500
@@ -116,7 +116,17 @@
/// of addition to the list.
SimObject *destObject; ///< Object on which this event will be applied.
- SimEvent() { destObject = NULL; }
+ // GDS ***************************************************************
+ bool paused; // allow a schedule to be paused
+ SimTime duration; // time between when event was posted to when it should occur
+ SimTime originalStartTime; // this will be different from startTime if event was paused
+ SimTime remainingTime; // amount of time remaining (used for resume)
+ // GDS ***************************************************************
+
+ // GDS ***************************************************************
+ SimEvent() { destObject = NULL; paused = false; remainingTime = 0; sequenceCount = 0; }
+ // GDS ***************************************************************
+
virtual ~SimEvent() {} ///< Destructor
///
/// A dummy virtual destructor is required
@@ -135,6 +145,11 @@
///
/// @param object Object stored in destObject.
virtual void process(SimObject *object)=0;
+
+ // GDS ***************************************************************
+ virtual void pause();
+ virtual void resume();
+ // GDS ***************************************************************
};
/// Implementation of schedule() function.
@@ -147,6 +162,7 @@
S32 mArgc;
char **mArgv;
bool mOnObject;
+
public:
/// Constructor
@@ -1355,6 +1371,12 @@
return postEvent(obj,evt,getCurrentTime());
}
+ // GDS ***************************************************************
+ void pauseEvent( U32 eventId );
+ void resumeEvent( U32 eventId );
+ bool isEventPaused( U32 eventId );
+ // GDS ***************************************************************
+
void cancelEvent(U32 eventId);
bool isEventPending(U32 eventId);
U32 getEventTimeLeft(U32 eventId);simBase.cc
--- original_simBase.cc 2006-03-19 11:18:04.000000000 -0600
+++ simBase.cc 2006-04-22 19:46:27.740312000 -0500
@@ -518,6 +518,24 @@
Sim::cancelEvent(dAtoi(argv[1]));
}
+// GDS ***************************************************************
+ConsoleFunction(pauseEvent,void,2,2,"pauseEvent(%scheduleId);")
+{
+ argc;
+ Sim::pauseEvent(dAtoi(argv[1]));
+}
+ConsoleFunction(resumeEvent,void,2,2,"resumeEvent(%scheduleId);")
+{
+ argc;
+ Sim::resumeEvent(dAtoi(argv[1]));
+}
+ConsoleFunction(isEventPaused,bool,2,2,"isEventPaused(%scheduleId);")
+{
+ argc;
+ return Sim::isEventPaused(dAtoi(argv[1]));
+}
+// GDS ***************************************************************
+
ConsoleFunction(isEventPending, bool, 2, 2, "isEventPending(%scheduleId);")
{
argc;
@@ -554,7 +572,12 @@
}
SimConsoleEvent *evt = new SimConsoleEvent(argc - 3, argv + 3, false);
- S32 ret = Sim::postEvent(refObject, evt, Sim::getCurrentTime() + timeDelta);
+ // GDS ***************************************************************
+ evt->originalStartTime = Sim::getCurrentTime();
+ evt->duration = timeDelta;
+ S32 ret = Sim::postEvent(refObject, evt, evt->originalStartTime + evt->duration);
+ // GDS ***************************************************************
+
// #ifdef DEBUG
// Con::printf("ref %s schedule(%s) = %d", argv[2], argv[3], ret);
// Con::executef(1, "backtrace");
@@ -691,7 +714,13 @@
argv[2] = argv[3];
argv[3] = argv[1];
SimConsoleEvent *evt = new SimConsoleEvent(argc - 2, argv + 2, true);
- S32 ret = Sim::postEvent(object, evt, Sim::getCurrentTime() + timeDelta);
+
+ // GDS ***************************************************************
+ evt->originalStartTime = Sim::getCurrentTime();
+ evt->duration = timeDelta;
+ S32 ret = Sim::postEvent(object, evt, evt->originalStartTime + evt->duration);
+ // GDS ***************************************************************
+
// #ifdef DEBUG
// Con::printf("obj %s schedule(%s) = %d", argv[3], argv[2], ret);
// Con::executef(1, "backtrace");
@@ -1841,6 +1870,22 @@
Con::execute(mArgc, const_cast<const char**>( mArgv ));
}
+// GDS ***************************************************************
+void SimEvent::pause()
+{
+ paused = true;
+ remainingTime = time - Sim::getCurrentTime();
+}
+
+void SimEvent::resume()
+{
+ paused = false;
+ time = Sim::getCurrentTime() + remainingTime;
+ startTime = Sim::getCurrentTime();
+}
+// GDS ***************************************************************
+
+
//-----------------------------------------------------------------------------
SimConsoleThreadExecCallback::SimConsoleThreadExecCallback() : retVal(NULL)simManager.cc
--- original_simManager.cc 2006-03-02 09:26:54.000000000 -0600
+++ simManager.cc 2006-04-22 19:55:36.879936000 -0500
@@ -75,6 +75,11 @@
Mutex::lockMutex(gEventQueueMutex);
+ // GDS ***************************************************************
+ // for some reason this line was missing.. should have been here
+ event->startTime = gCurrentTime;
+ // GDS ***************************************************************
+
event->time = time;
event->destObject = destObject;
@@ -86,7 +91,17 @@
return InvalidEventId;
}
- event->sequenceCount = gEventSequence++;
+
+ // GDS ***************************************************************
+ // only assign a sequence count if we don't already have one;
+ // This was changed so that paused events that are resumed later still
+ // have the same sequence Id; this is vital so that ids returned by
+ // schedule() are still valid.
+
+ if (!event->sequenceCount)
+ event->sequenceCount = gEventSequence++;
+ // GDS ***************************************************************
+
SimEvent **walk = &gEventQueue;
SimEvent *current;
@@ -134,6 +149,64 @@
Mutex::unlockMutex(gEventQueueMutex);
}
+// GDS ***************************************************************
+void pauseEvent(U32 eventSequence)
+{
+ Mutex::lockMutex(gEventQueueMutex);
+
+ SimEvent **walk = &gEventQueue;
+ SimEvent *current;
+
+ while((current = *walk) != NULL)
+ {
+ if(current->sequenceCount == eventSequence)
+ {
+ current->pause(); // if we found the event, pause it
+ Mutex::unlockMutex(gEventQueueMutex);
+ return;
+ }
+ else
+ walk = &(current->nextEvent);
+ }
+
+ Mutex::unlockMutex(gEventQueueMutex);
+}
+void resumeEvent(U32 eventSequence)
+{
+ Mutex::lockMutex(gEventQueueMutex);
+
+ SimEvent **walk = &gEventQueue;
+ SimEvent *current;
+
+ while((current = *walk) != NULL)
+ {
+ if(current->sequenceCount == eventSequence)
+ {
+ current->resume(); // if we found the event, resume it
+ Mutex::unlockMutex(gEventQueueMutex);
+ return;
+ }
+ else
+ walk = &(current->nextEvent);
+ }
+
+ Mutex::unlockMutex(gEventQueueMutex);
+}
+bool isEventPaused(U32 eventSequence)
+{
+ Mutex::lockMutex(gEventQueueMutex);
+
+ for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
+ if(walk->sequenceCount == eventSequence && walk->paused)
+ {
+ Mutex::unlockMutex(gEventQueueMutex);
+ return true;
+ }
+ Mutex::unlockMutex(gEventQueueMutex);
+ return false;
+}
+// GDS ***************************************************************
+
static void cancelPendingEvents(SimObject *obj)
{
Mutex::lockMutex(gEventQueueMutex);
@@ -178,9 +251,22 @@
for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
if(walk->sequenceCount == eventSequence)
{
- SimTime t = walk->time - getCurrentTime();
- Mutex::unlockMutex(gEventQueueMutex);
- return t;
+ // GDS ***************************************************************
+ if (walk->paused)
+ {
+ // if the event is paused, return the remaining time (this won't
+ // change until the event is resumed)
+ SimTime r = walk->remainingTime;
+ Mutex::unlockMutex(gEventQueueMutex);
+ return r;
+ }
+ else
+ {
+ SimTime t = walk->time - gCurrentTime;
+ Mutex::unlockMutex(gEventQueueMutex);
+ return t;
+ }
+ // GDS ***************************************************************
}
Mutex::unlockMutex(gEventQueueMutex);
@@ -192,7 +278,10 @@
{
for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
if(walk->sequenceCount == eventSequence)
- return (walk->time-walk->startTime);
+ // GDS ***************************************************************
+ return (walk->duration);
+ // GDS ***************************************************************
+
return 0;
}
@@ -200,7 +289,13 @@
{
for(SimEvent *walk = gEventQueue; walk; walk = walk->nextEvent)
if(walk->sequenceCount == eventSequence)
- return (getCurrentTime()-walk->startTime);
+ // GDS ***************************************************************
+ // This will return the total time passed since the event was first
+ // started--this may be greater than getScheduleDuration() if the
+ // event has been paused
+ return (getCurrentTime() - walk->originalStartTime);
+ // GDS ***************************************************************
+
return 0;
}
@@ -213,18 +308,32 @@
Mutex::lockMutex(gEventQueueMutex);
gTargetTime = targetTime;
+
while(gEventQueue && gEventQueue->time <= targetTime)
{
SimEvent *event = gEventQueue;
gEventQueue = gEventQueue->nextEvent;
+
AssertFatal(event->time >= gCurrentTime,
"SimEventQueue::pop: Cannot go back in time (flux capacitor not installed - BJG).");
gCurrentTime = event->time;
SimObject *obj = event->destObject;
- if(!obj->isDeleted())
- event->process(obj);
- delete event;
+ // GDS ***************************************************************
+ // only process the event if the event is not paused
+ if (!event->paused)
+ {
+ if(!obj->isDeleted())
+ event->process(obj);
+
+ delete event;
+ }
+ else
+ {
+ // reschedule the event
+ Sim::postEvent( obj, event, gCurrentTime + event->remainingTime );
+ }
+ // GDS ***************************************************************
}
gCurrentTime = targetTime;
Mutex::unlockMutex(gEventQueueMutex);