From 7683d941007bc2aff94282afde0338b4c37304a9 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 11 Oct 2008 14:49:10 +0000 Subject: [PATCH] add TaskManager- events --- panda/src/event/asyncTask.cxx | 20 ++++++- panda/src/event/asyncTask.h | 2 +- panda/src/event/asyncTaskChain.cxx | 4 +- panda/src/event/asyncTaskManager.cxx | 6 +-- panda/src/event/asyncTaskSequence.cxx | 11 ++-- panda/src/event/asyncTaskSequence.h | 2 +- panda/src/event/genericAsyncTask.cxx | 9 ++-- panda/src/event/genericAsyncTask.h | 2 +- panda/src/event/pythonTask.cxx | 78 +++++++++++++++++++-------- panda/src/event/pythonTask.h | 5 +- 10 files changed, 98 insertions(+), 41 deletions(-) diff --git a/panda/src/event/asyncTask.cxx b/panda/src/event/asyncTask.cxx index 7fb00ad451..52b97e4f61 100644 --- a/panda/src/event/asyncTask.cxx +++ b/panda/src/event/asyncTask.cxx @@ -445,6 +445,11 @@ do_task() { //////////////////////////////////////////////////////////////////// void AsyncTask:: upon_birth() { + // Throw a generic add event for the manager. + string add_name = _manager->get_name() + "-addTask"; + PT_Event event = new Event(add_name); + event->add_parameter(EventParameter(this)); + throw_event(event); } //////////////////////////////////////////////////////////////////// @@ -455,7 +460,10 @@ upon_birth() { // 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()). +// reason (e.g. AsyncTaskManager::remove()). By the +// time this method is called, _manager has been +// cleared, so the parameter manager indicates the +// original AsyncTaskManager that owned this task. // // The normal behavior is to throw the done_event only // if clean_exit is true. @@ -463,10 +471,18 @@ upon_birth() { // This function is called with the lock *not* held. //////////////////////////////////////////////////////////////////// void AsyncTask:: -upon_death(bool clean_exit) { +upon_death(AsyncTaskManager *manager, bool clean_exit) { if (clean_exit && !_done_event.empty()) { PT_Event event = new Event(_done_event); event->add_parameter(EventParameter(this)); throw_event(event); } + + // Also throw a generic remove event for the manager. + if (manager != (AsyncTaskManager *)NULL) { + string remove_name = manager->get_name() + "-removeTask"; + PT_Event event = new Event(remove_name); + event->add_parameter(EventParameter(this)); + throw_event(event); + } } diff --git a/panda/src/event/asyncTask.h b/panda/src/event/asyncTask.h index 4dc9b384a8..13297f6b33 100644 --- a/panda/src/event/asyncTask.h +++ b/panda/src/event/asyncTask.h @@ -119,7 +119,7 @@ protected: virtual bool is_runnable(); virtual DoneStatus do_task(); virtual void upon_birth(); - virtual void upon_death(bool clean_exit); + virtual void upon_death(AsyncTaskManager *manager, bool clean_exit); protected: AtomicAdjust::Integer _task_id; diff --git a/panda/src/event/asyncTaskChain.cxx b/panda/src/event/asyncTaskChain.cxx index 730818cf54..9e44a5f4e6 100644 --- a/panda/src/event/asyncTaskChain.cxx +++ b/panda/src/event/asyncTaskChain.cxx @@ -645,7 +645,7 @@ do_cleanup() { // Now go back and call the upon_death functions. _manager->_lock.release(); for (ti = dead.begin(); ti != dead.end(); ++ti) { - (*ti)->upon_death(false); + (*ti)->upon_death(_manager, false); } _manager->_lock.lock(); @@ -843,7 +843,7 @@ cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit) { if (upon_death) { _manager->_lock.release(); - task->upon_death(clean_exit); + task->upon_death(_manager, clean_exit); _manager->_lock.lock(); } } diff --git a/panda/src/event/asyncTaskManager.cxx b/panda/src/event/asyncTaskManager.cxx index 8d06a17716..af96fd65f3 100644 --- a/panda/src/event/asyncTaskManager.cxx +++ b/panda/src/event/asyncTaskManager.cxx @@ -15,8 +15,6 @@ #include "asyncTaskManager.h" #include "event.h" #include "pt_Event.h" -#include "throw_event.h" -#include "eventParameter.h" #include "mutexHolder.h" #include "indent.h" #include "pStatClient.h" @@ -375,7 +373,7 @@ remove(const AsyncTaskCollection &tasks) { } if (task->_chain->do_remove(task)) { _lock.release(); - task->upon_death(false); + task->upon_death(this, false); _lock.lock(); ++num_removed; } else { @@ -727,5 +725,5 @@ void AsyncTaskManager:: make_global_ptr() { nassertv(_global_ptr == (AsyncTaskManager *)NULL); - _global_ptr = new AsyncTaskManager("taskMgr"); + _global_ptr = new AsyncTaskManager("TaskManager"); } diff --git a/panda/src/event/asyncTaskSequence.cxx b/panda/src/event/asyncTaskSequence.cxx index 99a6397fda..9d567da5a8 100644 --- a/panda/src/event/asyncTaskSequence.cxx +++ b/panda/src/event/asyncTaskSequence.cxx @@ -146,7 +146,10 @@ upon_birth() { // 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()). +// reason (e.g. AsyncTaskManager::remove()). By the +// time this method is called, _manager has been +// cleared, so the parameter manager indicates the +// original AsyncTaskManager that owned this task. // // The normal behavior is to throw the done_event only // if clean_exit is true. @@ -156,8 +159,8 @@ upon_birth() { // return with it held. //////////////////////////////////////////////////////////////////// void AsyncTaskSequence:: -upon_death(bool clean_exit) { - AsyncTask::upon_death(clean_exit); +upon_death(AsyncTaskManager *manager, bool clean_exit) { + AsyncTask::upon_death(manager, clean_exit); set_current_task(NULL, clean_exit); } @@ -177,7 +180,7 @@ set_current_task(AsyncTask *task, bool clean_exit) { 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->upon_death(_manager, clean_exit); _current_task->_manager = NULL; } diff --git a/panda/src/event/asyncTaskSequence.h b/panda/src/event/asyncTaskSequence.h index d89aa69376..66f813c6bf 100644 --- a/panda/src/event/asyncTaskSequence.h +++ b/panda/src/event/asyncTaskSequence.h @@ -49,7 +49,7 @@ protected: virtual bool is_runnable(); virtual DoneStatus do_task(); virtual void upon_birth(); - virtual void upon_death(bool clean_exit); + virtual void upon_death(AsyncTaskManager *manager, bool clean_exit); private: void set_current_task(AsyncTask *task, bool clean_exit); diff --git a/panda/src/event/genericAsyncTask.cxx b/panda/src/event/genericAsyncTask.cxx index f39d196694..dd198aa652 100644 --- a/panda/src/event/genericAsyncTask.cxx +++ b/panda/src/event/genericAsyncTask.cxx @@ -101,7 +101,10 @@ upon_birth() { // 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()). +// reason (e.g. AsyncTaskManager::remove()). By the +// time this method is called, _manager has been +// cleared, so the parameter manager indicates the +// original AsyncTaskManager that owned this task. // // The normal behavior is to throw the done_event only // if clean_exit is true. @@ -109,8 +112,8 @@ upon_birth() { // This function is called with the lock *not* held. //////////////////////////////////////////////////////////////////// void GenericAsyncTask:: -upon_death(bool clean_exit) { - AsyncTask::upon_death(clean_exit); +upon_death(AsyncTaskManager *manager, bool clean_exit) { + AsyncTask::upon_death(manager, clean_exit); if (_upon_death != NULL) { (*_upon_death)(this, clean_exit, _user_data); diff --git a/panda/src/event/genericAsyncTask.h b/panda/src/event/genericAsyncTask.h index 15e2d7e783..d6cd94b45c 100644 --- a/panda/src/event/genericAsyncTask.h +++ b/panda/src/event/genericAsyncTask.h @@ -51,7 +51,7 @@ protected: virtual bool is_runnable(); virtual DoneStatus do_task(); virtual void upon_birth(); - virtual void upon_death(bool clean_exit); + virtual void upon_death(AsyncTaskManager *manager, bool clean_exit); private: TaskFunc *_function; diff --git a/panda/src/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index c27f0f0140..114073fcb3 100644 --- a/panda/src/event/pythonTask.cxx +++ b/panda/src/event/pythonTask.cxx @@ -205,7 +205,7 @@ get_upon_death() { void PythonTask:: set_owner(PyObject *owner) { if (_owner != NULL && _owner != Py_None && _state != S_inactive) { - upon_death(false); + unregister_from_owner(); } Py_XDECREF(_owner); @@ -213,7 +213,7 @@ set_owner(PyObject *owner) { Py_INCREF(_owner); if (_owner != Py_None && _state != S_inactive) { - upon_birth(); + register_to_owner(); } } @@ -477,7 +477,54 @@ do_python_task() { void PythonTask:: upon_birth() { AsyncTask::upon_birth(); + register_to_owner(); +} +//////////////////////////////////////////////////////////////////// +// Function: PythonTask::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()). By the +// time this method is called, _manager has been +// cleared, so the parameter manager indicates the +// original AsyncTaskManager that owned this task. +// +// The normal behavior is to throw the done_event only +// if clean_exit is true. +// +// This function is called with the lock *not* held. +//////////////////////////////////////////////////////////////////// +void PythonTask:: +upon_death(AsyncTaskManager *manager, bool clean_exit) { + AsyncTask::upon_death(manager, clean_exit); + + if (_upon_death != Py_None) { +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + // Use PyGILState to protect this asynchronous call. + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + + call_function(_upon_death); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif + } + unregister_from_owner(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PythonTask::register_to_owner +// Access: Private +// Description: Tells the owner we are now his task. +//////////////////////////////////////////////////////////////////// +void PythonTask:: +register_to_owner() { if (_owner != Py_None) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) // Use PyGILState to protect this asynchronous call. @@ -494,25 +541,13 @@ upon_birth() { } //////////////////////////////////////////////////////////////////// -// Function: PythonTask::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 *not* held. +// Function: PythonTask::unregister_from_owner +// Access: Private +// Description: Tells the owner we are no longer his task. //////////////////////////////////////////////////////////////////// void PythonTask:: -upon_death(bool clean_exit) { - AsyncTask::upon_death(clean_exit); - - if (_owner != Py_None && _upon_death != Py_None) { +unregister_from_owner() { + if (_owner != Py_None) { #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) // Use PyGILState to protect this asynchronous call. PyGILState_STATE gstate; @@ -520,7 +555,6 @@ upon_death(bool clean_exit) { #endif call_owner_method("_clearTask"); - call_function(_upon_death); #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) PyGILState_Release(gstate); @@ -530,7 +564,7 @@ upon_death(bool clean_exit) { //////////////////////////////////////////////////////////////////// // Function: PythonTask::call_owner_method -// Access: Protected +// Access: Private // Description: Calls the indicated method name on the given object, // if defined, passing in the task object as the only // parameter. @@ -555,7 +589,7 @@ call_owner_method(const char *method_name) { //////////////////////////////////////////////////////////////////// // Function: PythonTask::call_function -// Access: Protected +// Access: Private // Description: Calls the indicated Python function, passing in the // task object as the only parameter. //////////////////////////////////////////////////////////////////// diff --git a/panda/src/event/pythonTask.h b/panda/src/event/pythonTask.h index 13526e85a5..f29bcd016d 100644 --- a/panda/src/event/pythonTask.h +++ b/panda/src/event/pythonTask.h @@ -52,8 +52,11 @@ protected: virtual DoneStatus do_task(); DoneStatus do_python_task(); virtual void upon_birth(); - virtual void upon_death(bool clean_exit); + virtual void upon_death(AsyncTaskManager *manager, bool clean_exit); +private: + void register_to_owner(); + void unregister_from_owner(); void call_owner_method(const char *method_name); void call_function(PyObject *function);