mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-18 12:43:44 -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]
|
||||
# handle a missing object after it is already gone?
|
||||
if (av.isEmpty()):
|
||||
task.delayTime = 1.0
|
||||
task.setDelay(1.0)
|
||||
del self.gridObjects[avId]
|
||||
continue
|
||||
pos = av.getPos()
|
||||
@ -110,7 +110,7 @@ class DistributedCartesianGridAI(DistributedNodeAI, CartesianGridBase):
|
||||
self.handleAvatarZoneChange(av)
|
||||
# Do this every second, not every frame
|
||||
if (task):
|
||||
task.delayTime = 1.0
|
||||
task.setDelay(1.0)
|
||||
return Task.again
|
||||
|
||||
def handleAvatarZoneChange(self, av, useZoneId=-1):
|
||||
|
@ -100,7 +100,7 @@ class DistributedSmoothNodeBase:
|
||||
# startPosHprBroadcast; we should at least make an effort to keep
|
||||
# this task accurately aligned with its period and starting time.
|
||||
self.d_broadcastPosHpr()
|
||||
task.delayTime = self.__broadcastPeriod
|
||||
task.setDelay(self.__broadcastPeriod)
|
||||
return Task.again
|
||||
|
||||
def sendCurrentPosition(self):
|
||||
|
@ -304,7 +304,7 @@ class DirectScrolledList(DirectFrame):
|
||||
def __incButtonDown(self, event):
|
||||
assert self.notify.debugStateCall(self)
|
||||
task = Task(self.__scrollByTask)
|
||||
task.delayTime = (1.0 / self.scrollSpeed)
|
||||
task.setDelay(1.0 / self.scrollSpeed)
|
||||
task.prevTime = 0.0
|
||||
task.delta = 1
|
||||
taskName = self.taskName("scroll")
|
||||
@ -316,7 +316,7 @@ class DirectScrolledList(DirectFrame):
|
||||
def __decButtonDown(self, event):
|
||||
assert self.notify.debugStateCall(self)
|
||||
task = Task(self.__scrollByTask)
|
||||
task.delayTime = (1.0 / self.scrollSpeed)
|
||||
task.setDelay(1.0 / self.scrollSpeed)
|
||||
task.prevTime = 0.0
|
||||
task.delta = -1
|
||||
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