|
@@ -6,7 +6,7 @@ import time
|
|
|
import fnmatch
|
|
import fnmatch
|
|
|
import string
|
|
import string
|
|
|
import signal
|
|
import signal
|
|
|
-
|
|
|
|
|
|
|
+from bisect import bisect
|
|
|
|
|
|
|
|
# MRM: Need to make internal task variables like time, name, index
|
|
# MRM: Need to make internal task variables like time, name, index
|
|
|
# more unique (less likely to have name clashes)
|
|
# more unique (less likely to have name clashes)
|
|
@@ -110,6 +110,7 @@ class Task:
|
|
|
else:
|
|
else:
|
|
|
return ('Task id: %s, no name' % (self.id))
|
|
return ('Task id: %s, no name' % (self.id))
|
|
|
|
|
|
|
|
|
|
+
|
|
|
def pause(delayTime):
|
|
def pause(delayTime):
|
|
|
def func(self):
|
|
def func(self):
|
|
|
if (self.time < self.delayTime):
|
|
if (self.time < self.delayTime):
|
|
@@ -257,6 +258,24 @@ class TaskPriorityList(list):
|
|
|
self.__emptyIndex -= 1
|
|
self.__emptyIndex -= 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+class DoLaterList(list):
|
|
|
|
|
+ def __init__(self):
|
|
|
|
|
+ list.__init__(self)
|
|
|
|
|
+ self.__wakeTimeList = []
|
|
|
|
|
+
|
|
|
|
|
+ def add(self, task):
|
|
|
|
|
+ # Find the insertion point with a binary search
|
|
|
|
|
+ index = bisect(self.__wakeTimeList, task.wakeTime)
|
|
|
|
|
+ # Insert this new wake time
|
|
|
|
|
+ self.__wakeTimeList.insert(index, task.wakeTime)
|
|
|
|
|
+ # And the task itself
|
|
|
|
|
+ list.insert(self, index, task)
|
|
|
|
|
+
|
|
|
|
|
+ def __delitem__(self, index):
|
|
|
|
|
+ del self.__wakeTimeList[index]
|
|
|
|
|
+ list.__delitem__(self, index)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
class TaskManager:
|
|
class TaskManager:
|
|
|
|
|
|
|
|
notify = None
|
|
notify = None
|
|
@@ -267,7 +286,7 @@ class TaskManager:
|
|
|
self.taskList = []
|
|
self.taskList = []
|
|
|
# Dictionary of priority to newTaskLists
|
|
# Dictionary of priority to newTaskLists
|
|
|
self.pendingTaskDict = {}
|
|
self.pendingTaskDict = {}
|
|
|
- self.doLaterList = []
|
|
|
|
|
|
|
+ self.doLaterList = DoLaterList()
|
|
|
self.currentTime, self.currentFrame = self.__getTimeFrame()
|
|
self.currentTime, self.currentFrame = self.__getTimeFrame()
|
|
|
if (TaskManager.notify == None):
|
|
if (TaskManager.notify == None):
|
|
|
TaskManager.notify = directNotify.newCategory("TaskManager")
|
|
TaskManager.notify = directNotify.newCategory("TaskManager")
|
|
@@ -322,51 +341,43 @@ class TaskManager:
|
|
|
# Make a temp list of all the dolaters that expired this time
|
|
# Make a temp list of all the dolaters that expired this time
|
|
|
# through so we can remove them after we are done with the
|
|
# through so we can remove them after we are done with the
|
|
|
# for loop. Removing them during the for loop is a bad idea
|
|
# for loop. Removing them during the for loop is a bad idea
|
|
|
- removedTasks = []
|
|
|
|
|
- for dl in self.doLaterList:
|
|
|
|
|
|
|
+ while self.doLaterList:
|
|
|
|
|
+ # TODO: because this processor breaks out early, some tasks
|
|
|
|
|
+ # which have been flagged for removal may stay on the end of
|
|
|
|
|
+ # the doLaterList longer than expected. One brute force fix
|
|
|
|
|
+ # would be to cycle through all tasks removing the ones that
|
|
|
|
|
+ # are flagged each frame.
|
|
|
|
|
+ dl = self.doLaterList[0]
|
|
|
if dl.isRemoved():
|
|
if dl.isRemoved():
|
|
|
- removedTasks.append(dl)
|
|
|
|
|
|
|
+ del self.doLaterList[0]
|
|
|
continue
|
|
continue
|
|
|
# If the time now is less than the start of the doLater + delay
|
|
# If the time now is less than the start of the doLater + delay
|
|
|
# then we are not ready yet, continue to next one
|
|
# then we are not ready yet, continue to next one
|
|
|
- if task.time < dl.starttime + dl.delayTime:
|
|
|
|
|
|
|
+ elif task.time < dl.wakeTime:
|
|
|
# Since the list is sorted, the first one we get to, that
|
|
# Since the list is sorted, the first one we get to, that
|
|
|
# is not ready to go, we can return
|
|
# is not ready to go, we can return
|
|
|
break
|
|
break
|
|
|
else:
|
|
else:
|
|
|
assert(TaskManager.notify.debug('__doLaterProcessor: spawning %s' % (dl)))
|
|
assert(TaskManager.notify.debug('__doLaterProcessor: spawning %s' % (dl)))
|
|
|
- removedTasks.append(dl)
|
|
|
|
|
|
|
+ del self.doLaterList[0]
|
|
|
dl.setStartTimeFrame(self.currentTime, self.currentFrame)
|
|
dl.setStartTimeFrame(self.currentTime, self.currentFrame)
|
|
|
self.__addPendingTask(dl)
|
|
self.__addPendingTask(dl)
|
|
|
continue
|
|
continue
|
|
|
- # Get the tasks we spawned this frame off the doLaterList
|
|
|
|
|
- if removedTasks:
|
|
|
|
|
- self.doLaterList = unique(self.doLaterList, removedTasks)
|
|
|
|
|
return cont
|
|
return cont
|
|
|
|
|
|
|
|
def __spawnDoLater(self, task):
|
|
def __spawnDoLater(self, task):
|
|
|
assert(TaskManager.notify.debug('spawning doLater: %s' % (task)))
|
|
assert(TaskManager.notify.debug('spawning doLater: %s' % (task)))
|
|
|
# Add this task to the nameDict
|
|
# Add this task to the nameDict
|
|
|
- nameList = ifAbsentPut(self.nameDict, task.name, [])
|
|
|
|
|
|
|
+ nameList = self.nameDict.setdefault(task.name, [])
|
|
|
nameList.append(task)
|
|
nameList.append(task)
|
|
|
# be sure to ask the globalClock for the current frame time
|
|
# be sure to ask the globalClock for the current frame time
|
|
|
# rather than use a cached value; globalClock's frame time may
|
|
# rather than use a cached value; globalClock's frame time may
|
|
|
# have been synced since the start of this frame
|
|
# have been synced since the start of this frame
|
|
|
currentTime = globalClock.getFrameTime()
|
|
currentTime = globalClock.getFrameTime()
|
|
|
task.setStartTimeFrame(currentTime, self.currentFrame)
|
|
task.setStartTimeFrame(currentTime, self.currentFrame)
|
|
|
- # search from the beginning of the list to put this doLater in
|
|
|
|
|
- # the list in order of execution from earliest to latest
|
|
|
|
|
- # Assume it goes last unless we break out early
|
|
|
|
|
- index = len(self.doLaterList) + 1
|
|
|
|
|
- for i in range(len(self.doLaterList)):
|
|
|
|
|
- dl = self.doLaterList[i]
|
|
|
|
|
- # don't use the cached currentTime, use the one we just
|
|
|
|
|
- # got from globalClock. see comment above
|
|
|
|
|
- remainingTime = ((dl.starttime + dl.delayTime) - currentTime)
|
|
|
|
|
- if task.delayTime < remainingTime:
|
|
|
|
|
- index = i
|
|
|
|
|
- break
|
|
|
|
|
- self.doLaterList.insert(index, task)
|
|
|
|
|
|
|
+ # Cache the time we should wake up for easier sorting
|
|
|
|
|
+ task.wakeTime = task.starttime + task.delayTime
|
|
|
|
|
+ self.doLaterList.add(task)
|
|
|
if self.fVerbose:
|
|
if self.fVerbose:
|
|
|
# Alert the world, a new task is born!
|
|
# Alert the world, a new task is born!
|
|
|
messenger.send('TaskManager-spawnDoLater',
|
|
messenger.send('TaskManager-spawnDoLater',
|
|
@@ -410,7 +421,7 @@ class TaskManager:
|
|
|
# have been synced since the start of this frame
|
|
# have been synced since the start of this frame
|
|
|
currentTime = globalClock.getFrameTime()
|
|
currentTime = globalClock.getFrameTime()
|
|
|
task.setStartTimeFrame(currentTime, self.currentFrame)
|
|
task.setStartTimeFrame(currentTime, self.currentFrame)
|
|
|
- nameList = ifAbsentPut(self.nameDict, name, [])
|
|
|
|
|
|
|
+ nameList = self.nameDict.setdefault(name, [])
|
|
|
nameList.append(task)
|
|
nameList.append(task)
|
|
|
# Put it on the list for the end of this frame
|
|
# Put it on the list for the end of this frame
|
|
|
self.__addPendingTask(task)
|
|
self.__addPendingTask(task)
|
|
@@ -419,10 +430,14 @@ class TaskManager:
|
|
|
def __addPendingTask(self, task):
|
|
def __addPendingTask(self, task):
|
|
|
assert(TaskManager.notify.debug('__addPendingTask: %s' % (task.name)))
|
|
assert(TaskManager.notify.debug('__addPendingTask: %s' % (task.name)))
|
|
|
pri = task.getPriority()
|
|
pri = task.getPriority()
|
|
|
- taskPriList = ifAbsentPut(self.pendingTaskDict, pri, TaskPriorityList(pri))
|
|
|
|
|
|
|
+ if self.pendingTaskDict.has_key(pri):
|
|
|
|
|
+ taskPriList = self.pendingTaskDict[pri]
|
|
|
|
|
+ else:
|
|
|
|
|
+ taskPriList = TaskPriorityList(pri)
|
|
|
|
|
+ self.pendingTaskDict[pri] = taskPriList
|
|
|
taskPriList.add(task)
|
|
taskPriList.add(task)
|
|
|
|
|
|
|
|
- def __addNewTask(self, task):
|
|
|
|
|
|
|
+ def __addNewTask(self, task):
|
|
|
# The taskList is really an ordered list of TaskPriorityLists
|
|
# The taskList is really an ordered list of TaskPriorityLists
|
|
|
# search back from the end of the list until we find a
|
|
# search back from the end of the list until we find a
|
|
|
# taskList with a lower priority, or we hit the start of the list
|
|
# taskList with a lower priority, or we hit the start of the list
|
|
@@ -768,7 +783,7 @@ class TaskManager:
|
|
|
str = str + ' doLaterList\n'
|
|
str = str + ' doLaterList\n'
|
|
|
str = str + '---------------------------------------------------------------\n'
|
|
str = str + '---------------------------------------------------------------\n'
|
|
|
for task in self.doLaterList:
|
|
for task in self.doLaterList:
|
|
|
- remainingTime = ((task.starttime + task.delayTime) - self.currentTime)
|
|
|
|
|
|
|
+ remainingTime = ((task.wakeTime) - self.currentTime)
|
|
|
if task.isRemoved():
|
|
if task.isRemoved():
|
|
|
taskName = '(R)' + task.name
|
|
taskName = '(R)' + task.name
|
|
|
else:
|
|
else:
|