mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-19 13:15:00 -04:00
wip: starting experimental C-based task manager
This commit is contained in:
parent
524128b9fd
commit
cd8f9030d8
@ -100,7 +100,7 @@ class DistributedCartesianGridAI(DistributedNodeAI, CartesianGridBase):
|
|||||||
av = self.gridObjects[avId]
|
av = self.gridObjects[avId]
|
||||||
# handle a missing object after it is already gone?
|
# handle a missing object after it is already gone?
|
||||||
if (av.isEmpty()):
|
if (av.isEmpty()):
|
||||||
task.delayTime = 1.0
|
task.setDelay(1.0)
|
||||||
del self.gridObjects[avId]
|
del self.gridObjects[avId]
|
||||||
continue
|
continue
|
||||||
pos = av.getPos()
|
pos = av.getPos()
|
||||||
@ -110,7 +110,7 @@ class DistributedCartesianGridAI(DistributedNodeAI, CartesianGridBase):
|
|||||||
self.handleAvatarZoneChange(av)
|
self.handleAvatarZoneChange(av)
|
||||||
# Do this every second, not every frame
|
# Do this every second, not every frame
|
||||||
if (task):
|
if (task):
|
||||||
task.delayTime = 1.0
|
task.setDelay(1.0)
|
||||||
return Task.again
|
return Task.again
|
||||||
|
|
||||||
def handleAvatarZoneChange(self, av, useZoneId=-1):
|
def handleAvatarZoneChange(self, av, useZoneId=-1):
|
||||||
|
@ -100,7 +100,7 @@ class DistributedSmoothNodeBase:
|
|||||||
# startPosHprBroadcast; we should at least make an effort to keep
|
# startPosHprBroadcast; we should at least make an effort to keep
|
||||||
# this task accurately aligned with its period and starting time.
|
# this task accurately aligned with its period and starting time.
|
||||||
self.d_broadcastPosHpr()
|
self.d_broadcastPosHpr()
|
||||||
task.delayTime = self.__broadcastPeriod
|
task.setDelay(self.__broadcastPeriod)
|
||||||
return Task.again
|
return Task.again
|
||||||
|
|
||||||
def sendCurrentPosition(self):
|
def sendCurrentPosition(self):
|
||||||
|
@ -304,7 +304,7 @@ class DirectScrolledList(DirectFrame):
|
|||||||
def __incButtonDown(self, event):
|
def __incButtonDown(self, event):
|
||||||
assert self.notify.debugStateCall(self)
|
assert self.notify.debugStateCall(self)
|
||||||
task = Task(self.__scrollByTask)
|
task = Task(self.__scrollByTask)
|
||||||
task.delayTime = (1.0 / self.scrollSpeed)
|
task.setDelay(1.0 / self.scrollSpeed)
|
||||||
task.prevTime = 0.0
|
task.prevTime = 0.0
|
||||||
task.delta = 1
|
task.delta = 1
|
||||||
taskName = self.taskName("scroll")
|
taskName = self.taskName("scroll")
|
||||||
@ -316,7 +316,7 @@ class DirectScrolledList(DirectFrame):
|
|||||||
def __decButtonDown(self, event):
|
def __decButtonDown(self, event):
|
||||||
assert self.notify.debugStateCall(self)
|
assert self.notify.debugStateCall(self)
|
||||||
task = Task(self.__scrollByTask)
|
task = Task(self.__scrollByTask)
|
||||||
task.delayTime = (1.0 / self.scrollSpeed)
|
task.setDelay(1.0 / self.scrollSpeed)
|
||||||
task.prevTime = 0.0
|
task.prevTime = 0.0
|
||||||
task.delta = -1
|
task.delta = -1
|
||||||
taskName = self.taskName("scroll")
|
taskName = self.taskName("scroll")
|
||||||
|
File diff suppressed because it is too large
Load Diff
237
direct/src/task/TaskNew.py
Normal file
237
direct/src/task/TaskNew.py
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
""" This module defines a Python-level wrapper around the C++
|
||||||
|
AsyncTaskManager interface. It replaces the old full-Python
|
||||||
|
implementation of the Task system. """
|
||||||
|
|
||||||
|
from direct.directnotify.DirectNotifyGlobal import *
|
||||||
|
from direct.showbase import ExceptionVarDump
|
||||||
|
import signal
|
||||||
|
import types
|
||||||
|
|
||||||
|
from pandac.PandaModules import *
|
||||||
|
|
||||||
|
def print_exc_plus():
|
||||||
|
"""
|
||||||
|
Print the usual traceback information, followed by a listing of all the
|
||||||
|
local variables in each frame.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
tb = sys.exc_info()[2]
|
||||||
|
while 1:
|
||||||
|
if not tb.tb_next:
|
||||||
|
break
|
||||||
|
tb = tb.tb_next
|
||||||
|
stack = []
|
||||||
|
f = tb.tb_frame
|
||||||
|
while f:
|
||||||
|
stack.append(f)
|
||||||
|
f = f.f_back
|
||||||
|
stack.reverse()
|
||||||
|
traceback.print_exc()
|
||||||
|
print "Locals by frame, innermost last"
|
||||||
|
for frame in stack:
|
||||||
|
print
|
||||||
|
print "Frame %s in %s at line %s" % (frame.f_code.co_name,
|
||||||
|
frame.f_code.co_filename,
|
||||||
|
frame.f_lineno)
|
||||||
|
for key, value in frame.f_locals.items():
|
||||||
|
print "\t%20s = " % key,
|
||||||
|
#We have to be careful not to cause a new error in our error
|
||||||
|
#printer! Calling str() on an unknown object could cause an
|
||||||
|
#error we don't want.
|
||||||
|
try:
|
||||||
|
print value
|
||||||
|
except:
|
||||||
|
print "<ERROR WHILE PRINTING VALUE>"
|
||||||
|
|
||||||
|
# These constants are moved to the top level of the module,
|
||||||
|
# to make it easier for legacy code. In general though, putting
|
||||||
|
# constants at the top level of a module is deprecated.
|
||||||
|
|
||||||
|
done = AsyncTask.DSDone
|
||||||
|
cont = AsyncTask.DSCont
|
||||||
|
again = AsyncTask.DSAgain
|
||||||
|
|
||||||
|
class Task(PythonTask):
|
||||||
|
|
||||||
|
done = AsyncTask.DSDone
|
||||||
|
cont = AsyncTask.DSCont
|
||||||
|
again = AsyncTask.DSAgain
|
||||||
|
|
||||||
|
def __init__(self, function, name = ''):
|
||||||
|
PythonTask.__init__(self, function, name)
|
||||||
|
|
||||||
|
class TaskManager:
|
||||||
|
notify = directNotify.newCategory("TaskManager")
|
||||||
|
|
||||||
|
extendedExceptions = False
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.mgr = AsyncTaskManager('TaskManager')
|
||||||
|
|
||||||
|
self.resumeFunc = None
|
||||||
|
self.globalClock = None
|
||||||
|
self.stepping = False
|
||||||
|
self.running = False
|
||||||
|
self.fKeyboardInterrupt = False
|
||||||
|
self.interruptCount = 0
|
||||||
|
|
||||||
|
def keyboardInterruptHandler(self, signalNumber, stackFrame):
|
||||||
|
self.fKeyboardInterrupt = 1
|
||||||
|
self.interruptCount += 1
|
||||||
|
if self.interruptCount == 1:
|
||||||
|
print '* interrupt by keyboard'
|
||||||
|
elif self.interruptCount == 2:
|
||||||
|
print '** waiting for end of frame before interrupting...'
|
||||||
|
# The user must really want to interrupt this process
|
||||||
|
# Next time around invoke the default handler
|
||||||
|
signal.signal(signal.SIGINT, self.invokeDefaultHandler)
|
||||||
|
|
||||||
|
def hasTaskNamed(self, taskName):
|
||||||
|
return bool(self.mgr.findTask(taskName))
|
||||||
|
|
||||||
|
def getTasksNamed(self, taskName):
|
||||||
|
return self.__makeTaskList(self.mgr.findTasks(taskName))
|
||||||
|
|
||||||
|
def __makeTaskList(self, taskCollection):
|
||||||
|
l = []
|
||||||
|
for i in range(taskCollection.getNumTasks()):
|
||||||
|
l.append(taskCollection.getTask(i))
|
||||||
|
return l
|
||||||
|
|
||||||
|
def doMethodLater(self, delayTime, funcOrTask, name, extraArgs=None,
|
||||||
|
priority=0, appendTask=False, owner = None):
|
||||||
|
if delayTime < 0:
|
||||||
|
assert self.notify.warning('doMethodLater: added task: %s with negative delay: %s' % (name, delayTime))
|
||||||
|
|
||||||
|
task = self.__setupTask(funcOrTask, name, priority, extraArgs, appendTask)
|
||||||
|
task.setDelay(delayTime)
|
||||||
|
self.mgr.add(task)
|
||||||
|
return task
|
||||||
|
|
||||||
|
def add(self, funcOrTask, name, priority=0, extraArgs=None,
|
||||||
|
appendTask = False):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Add a new task to the taskMgr.
|
||||||
|
You can add a Task object or a method that takes one argument.
|
||||||
|
"""
|
||||||
|
task = self.__setupTask(funcOrTask, name, priority, extraArgs, appendTask)
|
||||||
|
self.mgr.add(task)
|
||||||
|
return task
|
||||||
|
|
||||||
|
def __setupTask(self, funcOrTask, name, priority, extraArgs, appendTask):
|
||||||
|
if isinstance(funcOrTask, PythonTask):
|
||||||
|
task = funcOrTask
|
||||||
|
elif callable(funcOrTask):
|
||||||
|
task = PythonTask(funcOrTask)
|
||||||
|
else:
|
||||||
|
self.notify.error(
|
||||||
|
'add: Tried to add a task that was not a Task or a func')
|
||||||
|
assert isinstance(name, types.StringTypes), 'Name must be a string type'
|
||||||
|
task.setName(name)
|
||||||
|
task.setSort(priority)
|
||||||
|
|
||||||
|
if extraArgs == None:
|
||||||
|
extraArgs = []
|
||||||
|
appendTask = True
|
||||||
|
task.setArgs(extraArgs, appendTask)
|
||||||
|
|
||||||
|
return task
|
||||||
|
|
||||||
|
def remove(self, taskOrName):
|
||||||
|
if isinstance(taskOrName, types.StringTypes):
|
||||||
|
tasks = self.mgr.findTasks(taskOrName)
|
||||||
|
return self.mgr.remove(tasks)
|
||||||
|
elif isinstance(taskOrName, AsyncTask):
|
||||||
|
return self.mgr.remove(taskOrName)
|
||||||
|
else:
|
||||||
|
self.notify.error('remove takes a string or a Task')
|
||||||
|
|
||||||
|
def removeTasksMatching(self, taskPattern):
|
||||||
|
"""removeTasksMatching(self, string taskPattern)
|
||||||
|
Removes tasks whose names match the pattern, which can include
|
||||||
|
standard shell globbing characters like *, ?, and [].
|
||||||
|
"""
|
||||||
|
tasks = self.mgr.findTasksMatching(GlobPattern(taskPattern))
|
||||||
|
return self.mgr.remove(tasks)
|
||||||
|
|
||||||
|
def step(self):
|
||||||
|
# Replace keyboard interrupt handler during task list processing
|
||||||
|
# so we catch the keyboard interrupt but don't handle it until
|
||||||
|
# after task list processing is complete.
|
||||||
|
self.fKeyboardInterrupt = 0
|
||||||
|
self.interruptCount = 0
|
||||||
|
signal.signal(signal.SIGINT, self.keyboardInterruptHandler)
|
||||||
|
|
||||||
|
self.mgr.poll()
|
||||||
|
|
||||||
|
# Restore default interrupt handler
|
||||||
|
signal.signal(signal.SIGINT, signal.default_int_handler)
|
||||||
|
if self.fKeyboardInterrupt:
|
||||||
|
raise KeyboardInterrupt
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Set the clock to have last frame's time in case we were
|
||||||
|
# Paused at the prompt for a long time
|
||||||
|
if self.globalClock:
|
||||||
|
t = self.globalClock.getFrameTime()
|
||||||
|
timeDelta = t - globalClock.getRealTime()
|
||||||
|
self.globalClock.setRealTime(t)
|
||||||
|
messenger.send("resetClock", [timeDelta])
|
||||||
|
|
||||||
|
if self.resumeFunc != None:
|
||||||
|
self.resumeFunc()
|
||||||
|
|
||||||
|
if self.stepping:
|
||||||
|
self.step()
|
||||||
|
else:
|
||||||
|
self.running = True
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
self.step()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.stop()
|
||||||
|
except IOError, ioError:
|
||||||
|
code, message = self._unpackIOError(ioError)
|
||||||
|
# Since upgrading to Python 2.4.1, pausing the execution
|
||||||
|
# often gives this IOError during the sleep function:
|
||||||
|
# IOError: [Errno 4] Interrupted function call
|
||||||
|
# So, let's just handle that specific exception and stop.
|
||||||
|
# All other IOErrors should still get raised.
|
||||||
|
# Only problem: legit IOError 4s will be obfuscated.
|
||||||
|
if code == 4:
|
||||||
|
self.stop()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
except Exception, e:
|
||||||
|
if self.extendedExceptions:
|
||||||
|
self.stop()
|
||||||
|
print_exc_plus()
|
||||||
|
else:
|
||||||
|
if (ExceptionVarDump.wantVariableDump and
|
||||||
|
ExceptionVarDump.dumpOnExceptionInit):
|
||||||
|
ExceptionVarDump._varDump__print(e)
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
if self.extendedExceptions:
|
||||||
|
self.stop()
|
||||||
|
print_exc_plus()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def _unpackIOError(self, ioError):
|
||||||
|
# IOError unpack from http://www.python.org/doc/essays/stdexceptions/
|
||||||
|
# this needs to be in its own method, exceptions that occur inside
|
||||||
|
# a nested try block are not caught by the inner try block's except
|
||||||
|
try:
|
||||||
|
(code, message) = ioError
|
||||||
|
except:
|
||||||
|
code = 0
|
||||||
|
message = ioError
|
||||||
|
return code, message
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
# Set a flag so we will stop before beginning next frame
|
||||||
|
self.running = False
|
1966
direct/src/task/TaskOrig.py
Normal file
1966
direct/src/task/TaskOrig.py
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user