mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
Task.sequence()
This commit is contained in:
parent
6599417ca1
commit
a6a4a893d0
@ -3,7 +3,8 @@ AsyncTaskManager interface. It replaces the old full-Python
|
||||
implementation of the Task system. """
|
||||
|
||||
__all__ = ['Task', 'TaskManager',
|
||||
'cont', 'done', 'again', 'pickup']
|
||||
'cont', 'done', 'again', 'pickup', 'exit',
|
||||
'sequence', 'loop', 'pause']
|
||||
|
||||
from direct.directnotify.DirectNotifyGlobal import *
|
||||
from direct.showbase import ExceptionVarDump
|
||||
@ -57,6 +58,7 @@ done = AsyncTask.DSDone
|
||||
cont = AsyncTask.DSCont
|
||||
again = AsyncTask.DSAgain
|
||||
pickup = AsyncTask.DSPickup
|
||||
exit = AsyncTask.DSExit
|
||||
|
||||
# Alias PythonTask to Task for historical purposes.
|
||||
Task = PythonTask
|
||||
@ -68,6 +70,26 @@ Task.DtoolClassDict['done'] = done
|
||||
Task.DtoolClassDict['cont'] = cont
|
||||
Task.DtoolClassDict['again'] = again
|
||||
Task.DtoolClassDict['pickup'] = pickup
|
||||
Task.DtoolClassDict['exit'] = exit
|
||||
|
||||
# Alias the AsyncTaskPause constructor as Task.pause().
|
||||
pause = AsyncTaskPause
|
||||
Task.DtoolClassDict['pause'] = staticmethod(pause)
|
||||
|
||||
def sequence(*taskList):
|
||||
seq = AsyncTaskSequence('sequence')
|
||||
for task in taskList:
|
||||
seq.addTask(task)
|
||||
return seq
|
||||
Task.DtoolClassDict['sequence'] = staticmethod(sequence)
|
||||
|
||||
def loop(*taskList):
|
||||
seq = AsyncTaskSequence('loop')
|
||||
for task in taskList:
|
||||
seq.addTask(task)
|
||||
seq.setRepeatCount(-1)
|
||||
return seq
|
||||
Task.DtoolClassDict['loop'] = staticmethod(loop)
|
||||
|
||||
class TaskManager:
|
||||
notify = directNotify.newCategory("TaskManager")
|
||||
@ -273,7 +295,7 @@ class TaskManager:
|
||||
return task
|
||||
|
||||
def __setupTask(self, funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath):
|
||||
if isinstance(funcOrTask, PythonTask):
|
||||
if isinstance(funcOrTask, AsyncTask):
|
||||
task = funcOrTask
|
||||
elif callable(funcOrTask):
|
||||
task = PythonTask(funcOrTask)
|
||||
@ -281,10 +303,15 @@ class TaskManager:
|
||||
self.notify.error(
|
||||
'add: Tried to add a task that was not a Task or a func')
|
||||
|
||||
if extraArgs is None:
|
||||
extraArgs = []
|
||||
appendTask = True
|
||||
task.setArgs(extraArgs, appendTask)
|
||||
if hasattr(task, 'setArgs'):
|
||||
# It will only accept arguments if it's a PythonTask.
|
||||
if extraArgs is None:
|
||||
extraArgs = []
|
||||
appendTask = True
|
||||
task.setArgs(extraArgs, appendTask)
|
||||
elif extraArgs is not None:
|
||||
self.notify.error(
|
||||
'Task %s does not accept arguments.' % (repr(task)))
|
||||
|
||||
if name is not None:
|
||||
assert isinstance(name, types.StringTypes), 'Name must be a string type'
|
||||
@ -301,11 +328,6 @@ class TaskManager:
|
||||
if sort is not None:
|
||||
task.setSort(sort)
|
||||
|
||||
if extraArgs is None:
|
||||
extraArgs = []
|
||||
appendTask = True
|
||||
task.setArgs(extraArgs, appendTask)
|
||||
|
||||
if taskChain is not None:
|
||||
task.setTaskChain(taskChain)
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
asyncTaskChain.h asyncTaskChain.I \
|
||||
asyncTaskCollection.h asyncTaskCollection.I \
|
||||
asyncTaskManager.h asyncTaskManager.I \
|
||||
asyncTaskPause.h asyncTaskPause.I \
|
||||
asyncTaskSequence.h asyncTaskSequence.I \
|
||||
config_event.h \
|
||||
buttonEvent.I buttonEvent.h \
|
||||
buttonEventList.I buttonEventList.h \
|
||||
@ -29,6 +31,8 @@
|
||||
asyncTaskChain.cxx \
|
||||
asyncTaskCollection.cxx \
|
||||
asyncTaskManager.cxx \
|
||||
asyncTaskPause.cxx \
|
||||
asyncTaskSequence.cxx \
|
||||
buttonEvent.cxx \
|
||||
buttonEventList.cxx \
|
||||
genericAsyncTask.cxx \
|
||||
@ -44,6 +48,8 @@
|
||||
asyncTaskChain.h asyncTaskChain.I \
|
||||
asyncTaskCollection.h asyncTaskCollection.I \
|
||||
asyncTaskManager.h asyncTaskManager.I \
|
||||
asyncTaskPause.h asyncTaskPause.I \
|
||||
asyncTaskSequence.h asyncTaskSequence.I \
|
||||
buttonEvent.I buttonEvent.h \
|
||||
buttonEventList.I buttonEventList.h \
|
||||
genericAsyncTask.h genericAsyncTask.I \
|
||||
|
@ -417,7 +417,14 @@ is_runnable() {
|
||||
// re-run the task again without waiting for the next
|
||||
// frame. Otherwise, run it next epoch as usual.
|
||||
//
|
||||
// DS_abort: abort the task, and interrupt the whole
|
||||
// DS_exit: stop the task, and stop the enclosing
|
||||
// sequence too. Outside of a sequence, this is the
|
||||
// same as DS_done.
|
||||
//
|
||||
// DS_pause: delay the task for set_delay() seconds,
|
||||
// then stop it. This is only useful within a sequence.
|
||||
//
|
||||
// DS_abort: stop the task, and interrupt the whole
|
||||
// AsyncTaskManager.
|
||||
//
|
||||
// This function is called with the lock *not* held.
|
||||
@ -433,9 +440,7 @@ do_task() {
|
||||
// Description: Override this function to do something useful when the
|
||||
// task has been added to the active queue.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTask::
|
||||
upon_birth() {
|
||||
@ -454,9 +459,7 @@ upon_birth() {
|
||||
// The normal behavior is to throw the done_event only
|
||||
// if clean_exit is true.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTask::
|
||||
upon_death(bool clean_exit) {
|
||||
@ -466,30 +469,3 @@ upon_death(bool clean_exit) {
|
||||
throw_event(event);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::release_lock
|
||||
// Access: Protected
|
||||
// Description: Releases the task lock. This is intended to be
|
||||
// used within callback functions, for instance
|
||||
// upon_birth() or upon_death(), as needed to release
|
||||
// the lock for processing. Be sure to grab it again
|
||||
// before returning.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTask::
|
||||
release_lock() {
|
||||
_manager->_lock.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::grab_lock
|
||||
// Access: Protected
|
||||
// Description: Releases the task lock. This is intended to be
|
||||
// used within callback functions, to grab the lock
|
||||
// after a previous call to release_lock().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTask::
|
||||
grab_lock() {
|
||||
_manager->_lock.lock();
|
||||
}
|
||||
|
||||
|
@ -44,16 +44,19 @@ class AsyncTaskChain;
|
||||
class EXPCL_PANDA_EVENT AsyncTask : public TypedReferenceCount, public Namable {
|
||||
public:
|
||||
AsyncTask(const string &name = string());
|
||||
virtual ~AsyncTask();
|
||||
ALLOC_DELETED_CHAIN(AsyncTask);
|
||||
|
||||
PUBLISHED:
|
||||
virtual ~AsyncTask();
|
||||
|
||||
enum DoneStatus {
|
||||
DS_done, // normal task completion
|
||||
DS_cont, // run task again next epoch
|
||||
DS_again, // start the task over from the beginning
|
||||
DS_pickup, // run task again this frame, if frame budget allows
|
||||
DS_abort, // abort the task and interrupt the whole task manager
|
||||
DS_exit, // stop the enclosing sequence
|
||||
DS_pause, // pause, then exit (useful within a sequence)
|
||||
DS_abort, // interrupt the task manager
|
||||
};
|
||||
|
||||
enum State {
|
||||
@ -62,6 +65,7 @@ PUBLISHED:
|
||||
S_servicing,
|
||||
S_servicing_removed, // Still servicing, but wants removal from manager.
|
||||
S_sleeping,
|
||||
S_active_nested, // active within a sequence.
|
||||
};
|
||||
|
||||
INLINE State get_state() const;
|
||||
@ -117,9 +121,6 @@ protected:
|
||||
virtual void upon_birth();
|
||||
virtual void upon_death(bool clean_exit);
|
||||
|
||||
void release_lock();
|
||||
void grab_lock();
|
||||
|
||||
protected:
|
||||
AtomicAdjust::Integer _task_id;
|
||||
string _chain_name;
|
||||
@ -172,6 +173,7 @@ private:
|
||||
|
||||
friend class AsyncTaskManager;
|
||||
friend class AsyncTaskChain;
|
||||
friend class AsyncTaskSequence;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const AsyncTask &task) {
|
||||
|
@ -494,7 +494,8 @@ do_add(AsyncTask *task) {
|
||||
// Access: Protected
|
||||
// Description: Removes the indicated task from this chain. Returns
|
||||
// true if removed, false otherwise. Assumes the lock
|
||||
// is already held.
|
||||
// is already held. The task->upon_death() method is
|
||||
// *not* called.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool AsyncTaskChain::
|
||||
do_remove(AsyncTask *task) {
|
||||
@ -521,7 +522,7 @@ do_remove(AsyncTask *task) {
|
||||
_sleeping.erase(_sleeping.begin() + index);
|
||||
make_heap(_sleeping.begin(), _sleeping.end(), AsyncTaskSortWakeTime());
|
||||
removed = true;
|
||||
cleanup_task(task);
|
||||
cleanup_task(task, false, false);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -542,7 +543,7 @@ do_remove(AsyncTask *task) {
|
||||
}
|
||||
}
|
||||
removed = true;
|
||||
cleanup_task(task);
|
||||
cleanup_task(task, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -607,23 +608,19 @@ do_cleanup() {
|
||||
TaskHeap::const_iterator ti;
|
||||
for (ti = active.begin(); ti != active.end(); ++ti) {
|
||||
AsyncTask *task = (*ti);
|
||||
cleanup_task(task);
|
||||
task->upon_death(false);
|
||||
cleanup_task(task, true, false);
|
||||
}
|
||||
for (ti = this_active.begin(); ti != this_active.end(); ++ti) {
|
||||
AsyncTask *task = (*ti);
|
||||
cleanup_task(task);
|
||||
task->upon_death(false);
|
||||
cleanup_task(task, true, false);
|
||||
}
|
||||
for (ti = next_active.begin(); ti != next_active.end(); ++ti) {
|
||||
AsyncTask *task = (*ti);
|
||||
cleanup_task(task);
|
||||
task->upon_death(false);
|
||||
cleanup_task(task, true, false);
|
||||
}
|
||||
for (ti = sleeping.begin(); ti != sleeping.end(); ++ti) {
|
||||
AsyncTask *task = (*ti);
|
||||
cleanup_task(task);
|
||||
task->upon_death(false);
|
||||
cleanup_task(task, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,13 +703,12 @@ service_one_task(AsyncTaskChain::AsyncTaskChainThread *thread) {
|
||||
if (task->_chain == this) {
|
||||
if (task->_state == AsyncTask::S_servicing_removed) {
|
||||
// This task wants to kill itself.
|
||||
cleanup_task(task);
|
||||
task->upon_death(false);
|
||||
cleanup_task(task, true, false);
|
||||
|
||||
} else if (task->_chain_name != get_name()) {
|
||||
// The task wants to jump to a different chain.
|
||||
PT(AsyncTask) hold_task = task;
|
||||
cleanup_task(task);
|
||||
cleanup_task(task, false, false);
|
||||
task->jump_to_task_chain(_manager);
|
||||
|
||||
} else {
|
||||
@ -752,8 +748,7 @@ service_one_task(AsyncTaskChain::AsyncTaskChainThread *thread) {
|
||||
|
||||
case AsyncTask::DS_abort:
|
||||
// The task had an exception and wants to raise a big flag.
|
||||
cleanup_task(task);
|
||||
task->upon_death(false);
|
||||
cleanup_task(task, true, false);
|
||||
if (_state == S_started) {
|
||||
_state = S_aborting;
|
||||
_cvar.signal_all();
|
||||
@ -762,8 +757,7 @@ service_one_task(AsyncTaskChain::AsyncTaskChainThread *thread) {
|
||||
|
||||
default:
|
||||
// The task has finished.
|
||||
cleanup_task(task);
|
||||
task->upon_death(true);
|
||||
cleanup_task(task, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -777,11 +771,15 @@ service_one_task(AsyncTaskChain::AsyncTaskChainThread *thread) {
|
||||
// interrupted) and is about to be removed from the
|
||||
// active queue. Assumes the lock is held.
|
||||
//
|
||||
// If upon_death is true, then task->upon_death() will
|
||||
// also be called, with the indicated clean_exit
|
||||
// parameter.
|
||||
//
|
||||
// Note that the lock may be temporarily released by
|
||||
// this method.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTaskChain::
|
||||
cleanup_task(AsyncTask *task) {
|
||||
cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit) {
|
||||
nassertv(task->_chain == this);
|
||||
PT(AsyncTask) hold_task = task;
|
||||
|
||||
@ -792,6 +790,12 @@ cleanup_task(AsyncTask *task) {
|
||||
--(_manager->_num_tasks);
|
||||
|
||||
_manager->remove_task_by_name(task);
|
||||
|
||||
if (upon_death) {
|
||||
_manager->_lock.release();
|
||||
task->upon_death(clean_exit);
|
||||
_manager->_lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -109,7 +109,7 @@ protected:
|
||||
int find_task_on_heap(const TaskHeap &heap, AsyncTask *task) const;
|
||||
|
||||
void service_one_task(AsyncTaskChainThread *thread);
|
||||
void cleanup_task(AsyncTask *task);
|
||||
void cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit);
|
||||
bool finish_sort_group();
|
||||
void filter_timeslice_priority();
|
||||
void do_stop_threads();
|
||||
|
@ -13,7 +13,6 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "asyncTaskCollection.h"
|
||||
|
||||
#include "indent.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -21,7 +21,11 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : AsyncTaskCollection
|
||||
// Description :
|
||||
// Description : A list of tasks, for instance as returned by some of
|
||||
// the AsyncTaskManager query functions. This also
|
||||
// serves to define an AsyncTaskSequence.
|
||||
//
|
||||
// TODO: None of this is thread-safe yet.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_PGRAPH AsyncTaskCollection {
|
||||
PUBLISHED:
|
||||
|
@ -199,34 +199,37 @@ void AsyncTaskManager::
|
||||
add(AsyncTask *task) {
|
||||
nassertv(task->is_runnable());
|
||||
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
if (task_cat.is_debug()) {
|
||||
task_cat.debug()
|
||||
<< "Adding " << *task << "\n";
|
||||
}
|
||||
|
||||
if (task->_state == AsyncTask::S_servicing_removed) {
|
||||
if (task->_manager == this) {
|
||||
// Re-adding a self-removed task; this just means clearing the
|
||||
// removed flag.
|
||||
task->_state = AsyncTask::S_servicing;
|
||||
return;
|
||||
{
|
||||
MutexHolder holder(_lock);
|
||||
|
||||
if (task_cat.is_debug()) {
|
||||
task_cat.debug()
|
||||
<< "Adding " << *task << "\n";
|
||||
}
|
||||
|
||||
if (task->_state == AsyncTask::S_servicing_removed) {
|
||||
if (task->_manager == this) {
|
||||
// Re-adding a self-removed task; this just means clearing the
|
||||
// removed flag.
|
||||
task->_state = AsyncTask::S_servicing;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nassertv(task->_manager == NULL &&
|
||||
task->_state == AsyncTask::S_inactive);
|
||||
nassertv(!do_has_task(task));
|
||||
|
||||
AsyncTaskChain *chain = do_find_task_chain(task->_chain_name);
|
||||
if (chain == (AsyncTaskChain *)NULL) {
|
||||
task_cat.warning()
|
||||
<< "Creating implicit AsyncTaskChain " << task->_chain_name
|
||||
<< " for " << get_type() << " " << get_name() << "\n";
|
||||
chain = do_make_task_chain(task->_chain_name);
|
||||
}
|
||||
chain->do_add(task);
|
||||
}
|
||||
|
||||
nassertv(task->_manager == NULL &&
|
||||
task->_state == AsyncTask::S_inactive);
|
||||
nassertv(!do_has_task(task));
|
||||
|
||||
AsyncTaskChain *chain = do_find_task_chain(task->_chain_name);
|
||||
if (chain == (AsyncTaskChain *)NULL) {
|
||||
task_cat.warning()
|
||||
<< "Creating implicit AsyncTaskChain " << task->_chain_name
|
||||
<< " for " << get_type() << " " << get_name() << "\n";
|
||||
chain = do_make_task_chain(task->_chain_name);
|
||||
}
|
||||
chain->do_add(task);
|
||||
task->upon_birth();
|
||||
}
|
||||
|
||||
@ -353,7 +356,7 @@ remove(const AsyncTaskCollection &tasks) {
|
||||
int num_tasks = tasks.get_num_tasks();
|
||||
int i;
|
||||
for (i = 0; i < num_tasks; ++i) {
|
||||
AsyncTask *task = tasks.get_task(i);
|
||||
PT(AsyncTask) task = tasks.get_task(i);
|
||||
|
||||
if (task->_manager != this) {
|
||||
// Not a member of this manager, or already removed.
|
||||
@ -365,7 +368,9 @@ remove(const AsyncTaskCollection &tasks) {
|
||||
<< "Removing " << *task << "\n";
|
||||
}
|
||||
if (task->_chain->do_remove(task)) {
|
||||
_lock.release();
|
||||
task->upon_death(false);
|
||||
_lock.lock();
|
||||
++num_removed;
|
||||
} else {
|
||||
if (task_cat.is_debug()) {
|
||||
|
@ -156,6 +156,7 @@ private:
|
||||
friend class AsyncTaskChain;
|
||||
friend class AsyncTaskChain::AsyncTaskChainThread;
|
||||
friend class AsyncTask;
|
||||
friend class AsyncTaskSequence;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const AsyncTaskManager &manager) {
|
||||
|
14
panda/src/event/asyncTaskPause.I
Normal file
14
panda/src/event/asyncTaskPause.I
Normal file
@ -0,0 +1,14 @@
|
||||
// Filename: asyncTaskPause.I
|
||||
// Created by: drose (04Oct08)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
42
panda/src/event/asyncTaskPause.cxx
Normal file
42
panda/src/event/asyncTaskPause.cxx
Normal file
@ -0,0 +1,42 @@
|
||||
// Filename: asyncTaskPause.cxx
|
||||
// Created by: drose (04Oct08)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "asyncTaskPause.h"
|
||||
|
||||
TypeHandle AsyncTaskPause::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskPause::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTaskPause::
|
||||
AsyncTaskPause(double delay) :
|
||||
AsyncTask("pause")
|
||||
{
|
||||
set_delay(delay);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskPause::do_task
|
||||
// Access: Protected, Virtual
|
||||
// Description: Override this function to do something useful for the
|
||||
// task.
|
||||
//
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::DoneStatus AsyncTaskPause::
|
||||
do_task() {
|
||||
return DS_pause;
|
||||
}
|
60
panda/src/event/asyncTaskPause.h
Normal file
60
panda/src/event/asyncTaskPause.h
Normal file
@ -0,0 +1,60 @@
|
||||
// Filename: asyncTaskPause.h
|
||||
// Created by: drose (04Oct08)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ASYNCTASKPAUSE_H
|
||||
#define ASYNCTASKPAUSE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "asyncTask.h"
|
||||
|
||||
class AsyncTaskManager;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : AsyncTaskPause
|
||||
// Description : A special kind of task that simple returns DS_pause,
|
||||
// to pause for a specified number of seconds and then
|
||||
// finish. It's intended to be used within an
|
||||
// AsyncTaskSequence.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_EVENT AsyncTaskPause : public AsyncTask {
|
||||
PUBLISHED:
|
||||
AsyncTaskPause(double delay);
|
||||
ALLOC_DELETED_CHAIN(AsyncTaskPause);
|
||||
|
||||
protected:
|
||||
virtual DoneStatus do_task();
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
AsyncTask::init_type();
|
||||
register_type(_type_handle, "AsyncTaskPause",
|
||||
AsyncTask::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "asyncTaskPause.I"
|
||||
|
||||
#endif
|
||||
|
51
panda/src/event/asyncTaskSequence.I
Normal file
51
panda/src/event/asyncTaskSequence.I
Normal file
@ -0,0 +1,51 @@
|
||||
// Filename: asyncTaskSequence.I
|
||||
// Created by: drose (04Oct08)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::set_repeat_count
|
||||
// Access: Published
|
||||
// Description: Sets the repeat count of the sequence. If the count
|
||||
// is 0 or 1, the sequence will run exactly once. If it
|
||||
// is greater than 0, it will run that number of times.
|
||||
// If it is negative, it will run forever until it is
|
||||
// explicitly removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void AsyncTaskSequence::
|
||||
set_repeat_count(int repeat_count) {
|
||||
_repeat_count = repeat_count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::get_repeat_count
|
||||
// Access: Published
|
||||
// Description: Returns the repeat count of the sequence. See
|
||||
// set_repeat_count().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int AsyncTaskSequence::
|
||||
get_repeat_count() const {
|
||||
return _repeat_count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::get_current_task_index
|
||||
// Access: Published
|
||||
// Description: Returns the index of the task within the sequence
|
||||
// that is currently being executed (or that will be
|
||||
// executed at the next epoch).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int AsyncTaskSequence::
|
||||
get_current_task_index() const {
|
||||
return _task_index;
|
||||
}
|
193
panda/src/event/asyncTaskSequence.cxx
Normal file
193
panda/src/event/asyncTaskSequence.cxx
Normal file
@ -0,0 +1,193 @@
|
||||
// Filename: asyncTaskSequence.cxx
|
||||
// Created by: drose (04Oct08)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "asyncTaskSequence.h"
|
||||
|
||||
TypeHandle AsyncTaskSequence::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTaskSequence::
|
||||
AsyncTaskSequence(const string &name) :
|
||||
AsyncTask(name),
|
||||
_repeat_count(0),
|
||||
_task_index(0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::Destructor
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTaskSequence::
|
||||
~AsyncTaskSequence() {
|
||||
set_current_task(NULL, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::is_runnable
|
||||
// Access: Protected, Virtual
|
||||
// Description: Override this function to return true if the task can
|
||||
// be successfully executed, false if it cannot. Mainly
|
||||
// intended as a sanity check when attempting to add the
|
||||
// task to a task manager.
|
||||
//
|
||||
// This function is called with the lock held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool AsyncTaskSequence::
|
||||
is_runnable() {
|
||||
return (get_num_tasks() > 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::do_task
|
||||
// Access: Protected, Virtual
|
||||
// Description: Override this function to do something useful for the
|
||||
// task.
|
||||
//
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::DoneStatus AsyncTaskSequence::
|
||||
do_task() {
|
||||
// Clear the delay that might have been set from a previous wait.
|
||||
_delay = 0.0;
|
||||
_has_delay = false;
|
||||
|
||||
if (_task_index >= get_num_tasks()) {
|
||||
// Ran off the end of the task list.
|
||||
set_current_task(NULL, true);
|
||||
_task_index = 0;
|
||||
if (_task_index >= get_num_tasks()) {
|
||||
return DS_done;
|
||||
}
|
||||
if (_repeat_count > 0) {
|
||||
--_repeat_count;
|
||||
}
|
||||
if (_repeat_count != 0) {
|
||||
return DS_cont;
|
||||
}
|
||||
return DS_done;
|
||||
}
|
||||
|
||||
AsyncTask *task = get_task(_task_index);
|
||||
set_current_task(task, true);
|
||||
nassertr(_current_task != (AsyncTask *)NULL, DS_exit);
|
||||
|
||||
DoneStatus result = _current_task->do_task();
|
||||
switch (result) {
|
||||
case DS_again:
|
||||
case DS_pause:
|
||||
// The task wants to sleep for a period of time.
|
||||
{
|
||||
double now = _manager->_clock->get_frame_time();
|
||||
_current_task->_start_time = now + _current_task->_delay;
|
||||
|
||||
_delay = _current_task->_delay;
|
||||
_has_delay = _current_task->_has_delay;
|
||||
|
||||
if (result == DS_pause) {
|
||||
// When it wakes up, move on to the next task.
|
||||
++_task_index;
|
||||
}
|
||||
}
|
||||
return DS_again;
|
||||
|
||||
case DS_done:
|
||||
// Go on to the next task.
|
||||
++_task_index;
|
||||
return DS_cont;
|
||||
|
||||
case DS_cont:
|
||||
case DS_pickup:
|
||||
case DS_exit:
|
||||
case DS_abort:
|
||||
// Just return these results through.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::upon_birth
|
||||
// Access: Protected, Virtual
|
||||
// Description: Override this function to do something useful when the
|
||||
// task has been added to the active queue.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTaskSequence::
|
||||
upon_birth() {
|
||||
AsyncTask::upon_birth();
|
||||
_task_index = 0;
|
||||
set_current_task(NULL, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::upon_death
|
||||
// Access: Protected, Virtual
|
||||
// Description: Override this function to do something useful when the
|
||||
// task has been removed from the active queue. The
|
||||
// parameter clean_exit is true if the task has been
|
||||
// removed because it exited normally (returning
|
||||
// DS_done), or false if it was removed for some other
|
||||
// reason (e.g. AsyncTaskManager::remove()).
|
||||
//
|
||||
// The normal behavior is to throw the done_event only
|
||||
// if clean_exit is true.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTaskSequence::
|
||||
upon_death(bool clean_exit) {
|
||||
AsyncTask::upon_death(clean_exit);
|
||||
set_current_task(NULL, clean_exit);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskSequence::set_current_task
|
||||
// Access: Private
|
||||
// Description: Sets the current executing task. If NULL, sets the
|
||||
// current task to NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTaskSequence::
|
||||
set_current_task(AsyncTask *task, bool clean_exit) {
|
||||
if (_current_task == task) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_current_task != (AsyncTask *)NULL) {
|
||||
nassertv(_current_task->_state == S_active_nested);
|
||||
nassertv(_current_task->_manager == _manager || _manager == NULL);
|
||||
_current_task->_state = S_inactive;
|
||||
_current_task->upon_death(clean_exit);
|
||||
_current_task->_manager = NULL;
|
||||
}
|
||||
|
||||
_current_task = task;
|
||||
|
||||
if (_current_task != (AsyncTask *)NULL) {
|
||||
nassertv(_current_task->_state == S_inactive);
|
||||
nassertv(_current_task->_manager == NULL);
|
||||
_current_task->_manager = _manager;
|
||||
_current_task->_state = S_active_nested;
|
||||
_current_task->upon_birth();
|
||||
}
|
||||
}
|
82
panda/src/event/asyncTaskSequence.h
Normal file
82
panda/src/event/asyncTaskSequence.h
Normal file
@ -0,0 +1,82 @@
|
||||
// Filename: asyncTaskSequence.h
|
||||
// Created by: drose (04Oct08)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
//
|
||||
// All use of this software is subject to the terms of the revised BSD
|
||||
// license. You should have received a copy of this license along
|
||||
// with this source code in a file named "LICENSE."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ASYNCTASKSEQUENCE_H
|
||||
#define ASYNCTASKSEQUENCE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "asyncTask.h"
|
||||
#include "asyncTaskCollection.h"
|
||||
|
||||
class AsyncTaskManager;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : AsyncTaskSequence
|
||||
// Description : A special kind of task that serves as a list of tasks
|
||||
// internally. Each task on the list is executed in
|
||||
// sequence, one per epoch.
|
||||
//
|
||||
// This is similar to a Sequence interval, though it has
|
||||
// some slightly different abilities. For instance,
|
||||
// although you can't start at any arbitrary point in
|
||||
// the sequence, you can construct a task sequence whose
|
||||
// duration changes during playback.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_EVENT AsyncTaskSequence : public AsyncTask, public AsyncTaskCollection {
|
||||
PUBLISHED:
|
||||
AsyncTaskSequence(const string &name);
|
||||
virtual ~AsyncTaskSequence();
|
||||
ALLOC_DELETED_CHAIN(AsyncTaskSequence);
|
||||
|
||||
INLINE void set_repeat_count(int repeat_count);
|
||||
INLINE int get_repeat_count() const;
|
||||
|
||||
INLINE int get_current_task_index() const;
|
||||
|
||||
protected:
|
||||
virtual bool is_runnable();
|
||||
virtual DoneStatus do_task();
|
||||
virtual void upon_birth();
|
||||
virtual void upon_death(bool clean_exit);
|
||||
|
||||
private:
|
||||
void set_current_task(AsyncTask *task, bool clean_exit);
|
||||
|
||||
int _repeat_count;
|
||||
int _task_index;
|
||||
PT(AsyncTask) _current_task;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
AsyncTask::init_type();
|
||||
register_type(_type_handle, "AsyncTaskSequence",
|
||||
AsyncTask::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "asyncTaskSequence.I"
|
||||
|
||||
#endif
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "asyncTask.h"
|
||||
#include "asyncTaskChain.h"
|
||||
#include "asyncTaskManager.h"
|
||||
#include "asyncTaskPause.h"
|
||||
#include "asyncTaskSequence.h"
|
||||
#include "buttonEventList.h"
|
||||
#include "event.h"
|
||||
#include "eventHandler.h"
|
||||
@ -34,6 +36,8 @@ ConfigureFn(config_event) {
|
||||
AsyncTask::init_type();
|
||||
AsyncTaskChain::init_type();
|
||||
AsyncTaskManager::init_type();
|
||||
AsyncTaskPause::init_type();
|
||||
AsyncTaskSequence::init_type();
|
||||
ButtonEventList::init_type();
|
||||
PointerEventList::init_type();
|
||||
Event::init_type();
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "asyncTaskChain.cxx"
|
||||
#include "asyncTaskCollection.cxx"
|
||||
#include "asyncTaskManager.cxx"
|
||||
#include "asyncTaskPause.cxx"
|
||||
#include "asyncTaskSequence.cxx"
|
||||
#include "buttonEvent.cxx"
|
||||
#include "buttonEventList.cxx"
|
||||
#include "genericAsyncTask.cxx"
|
||||
|
@ -65,7 +65,10 @@ is_runnable() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GenericAsyncTask::do_task
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
// Description: Override this function to do something useful for the
|
||||
// task.
|
||||
//
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::DoneStatus GenericAsyncTask::
|
||||
do_task() {
|
||||
@ -79,18 +82,14 @@ do_task() {
|
||||
// Description: Override this function to do something useful when the
|
||||
// task has been added to the active queue.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GenericAsyncTask::
|
||||
upon_birth() {
|
||||
AsyncTask::upon_birth();
|
||||
|
||||
if (_upon_birth != NULL) {
|
||||
release_lock();
|
||||
(*_upon_birth)(this, _user_data);
|
||||
grab_lock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,17 +106,13 @@ upon_birth() {
|
||||
// The normal behavior is to throw the done_event only
|
||||
// if clean_exit is true.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GenericAsyncTask::
|
||||
upon_death(bool clean_exit) {
|
||||
AsyncTask::upon_death(clean_exit);
|
||||
|
||||
if (_upon_death != NULL) {
|
||||
release_lock();
|
||||
(*_upon_death)(this, clean_exit, _user_data);
|
||||
grab_lock();
|
||||
}
|
||||
}
|
||||
|
@ -341,7 +341,10 @@ is_runnable() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PythonTask::do_task
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
// Description: Override this function to do something useful for the
|
||||
// task.
|
||||
//
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::DoneStatus PythonTask::
|
||||
do_task() {
|
||||
@ -434,6 +437,8 @@ do_python_task() {
|
||||
case DS_done:
|
||||
case DS_cont:
|
||||
case DS_pickup:
|
||||
case DS_exit:
|
||||
case DS_pause:
|
||||
// Legitimate value.
|
||||
Py_DECREF(result);
|
||||
return (DoneStatus)retval;
|
||||
@ -467,16 +472,13 @@ do_python_task() {
|
||||
// Description: Override this function to do something useful when the
|
||||
// task has been added to the active queue.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PythonTask::
|
||||
upon_birth() {
|
||||
AsyncTask::upon_birth();
|
||||
|
||||
if (_owner != Py_None) {
|
||||
release_lock();
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
// Use PyGILState to protect this asynchronous call.
|
||||
PyGILState_STATE gstate;
|
||||
@ -488,7 +490,6 @@ upon_birth() {
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
grab_lock();
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,16 +506,13 @@ upon_birth() {
|
||||
// The normal behavior is to throw the done_event only
|
||||
// if clean_exit is true.
|
||||
//
|
||||
// This function is called with the lock held. You may
|
||||
// temporarily release if it necessary, but be sure to
|
||||
// return with it held.
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PythonTask::
|
||||
upon_death(bool clean_exit) {
|
||||
AsyncTask::upon_death(clean_exit);
|
||||
|
||||
if (_owner != Py_None && _upon_death != Py_None) {
|
||||
release_lock();
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
// Use PyGILState to protect this asynchronous call.
|
||||
PyGILState_STATE gstate;
|
||||
@ -527,7 +525,6 @@ upon_death(bool clean_exit) {
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
grab_lock();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user