diff --git a/panda/src/event/asyncTaskChain.cxx b/panda/src/event/asyncTaskChain.cxx index 1c9651fb86..0a9e9c5ca2 100644 --- a/panda/src/event/asyncTaskChain.cxx +++ b/panda/src/event/asyncTaskChain.cxx @@ -1373,14 +1373,18 @@ thread_main() { // If we've exceeded our frame budget, sleep until the next // frame. - while (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) { - _chain->cleanup_pickup_mode(); - _chain->_manager->_frame_cvar.wait(); - frame = _chain->_manager->_clock->get_frame_count(); - if (_chain->_current_frame != frame) { - _chain->_current_frame = frame; - _chain->_time_in_frame = 0.0; + if (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) { + while (_chain->_frame_budget >= 0.0 && _chain->_time_in_frame >= _chain->_frame_budget) { + _chain->cleanup_pickup_mode(); + _chain->_manager->_frame_cvar.wait(); + frame = _chain->_manager->_clock->get_frame_count(); + if (_chain->_current_frame != frame) { + _chain->_current_frame = frame; + _chain->_time_in_frame = 0.0; + } } + // Now that it's the next frame, go back to the top of the loop. + continue; } PStatTimer timer(_task_pcollector); diff --git a/panda/src/event/pythonTask.cxx b/panda/src/event/pythonTask.cxx index 5dd6c39e3e..177d6b8a2b 100644 --- a/panda/src/event/pythonTask.cxx +++ b/panda/src/event/pythonTask.cxx @@ -313,6 +313,30 @@ __getattr__(const string &attr_name) const { //////////////////////////////////////////////////////////////////// AsyncTask::DoneStatus PythonTask:: do_task() { +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + // Use PyGILState to protect this asynchronous call. + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + + DoneStatus result = do_python_task(); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif + + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: PythonTask::do_python_task +// Access: Protected +// Description: The Python calls that implement do_task(). This +// function is separate so we can acquire the Python +// interpretor lock while it runs. +//////////////////////////////////////////////////////////////////// +AsyncTask::DoneStatus PythonTask:: +do_python_task() { PyObject *result = NULL; if (_generator == (PyObject *)NULL) { @@ -419,7 +443,18 @@ do_task() { void PythonTask:: upon_birth() { AsyncTask::upon_birth(); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + // Use PyGILState to protect this asynchronous call. + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + call_owner_method("_addTask"); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif } //////////////////////////////////////////////////////////////////// @@ -442,8 +477,19 @@ upon_birth() { void PythonTask:: upon_death(bool clean_exit) { AsyncTask::upon_death(clean_exit); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + // Use PyGILState to protect this asynchronous call. + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); +#endif + call_owner_method("_clearTask"); call_function(_upon_death); + +#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS) + PyGILState_Release(gstate); +#endif } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/event/pythonTask.h b/panda/src/event/pythonTask.h index 7c22d426e5..9d3e48d364 100644 --- a/panda/src/event/pythonTask.h +++ b/panda/src/event/pythonTask.h @@ -49,6 +49,7 @@ PUBLISHED: protected: virtual DoneStatus do_task(); + DoneStatus do_python_task(); virtual void upon_birth(); virtual void upon_death(bool clean_exit); diff --git a/panda/src/pipeline/conditionVarPosixImpl.cxx b/panda/src/pipeline/conditionVarPosixImpl.cxx index 085af4980b..a2162e5295 100644 --- a/panda/src/pipeline/conditionVarPosixImpl.cxx +++ b/panda/src/pipeline/conditionVarPosixImpl.cxx @@ -38,7 +38,7 @@ wait(double timeout) { int seconds = (int)floor(timeout); ts.tv_sec += seconds; - ts.tv_nsec += (timeout - seconds) * 1000000.0; + ts.tv_nsec += (int)((timeout - seconds) * 1000000.0); int result = pthread_cond_timedwait(&_cvar, &_mutex._lock, &ts); nassertv(result == 0); diff --git a/panda/src/pipeline/pythonThread.cxx b/panda/src/pipeline/pythonThread.cxx index 104945a756..c1ef41e344 100644 --- a/panda/src/pipeline/pythonThread.cxx +++ b/panda/src/pipeline/pythonThread.cxx @@ -50,12 +50,6 @@ PythonThread(PyObject *function, PyObject *args, nassert_raise("Invalid args passed to PythonThread constructor"); } } - -#ifndef SIMPLE_THREADS - // Ensure that the Python threading system is initialized and ready - // to go. - PyEval_InitThreads(); -#endif } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index af4c10fd06..62b84c2051 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -13,40 +13,6 @@ //////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////// -// Function: Thread::Constructor -// Access: Protected -// Description: Creates a new Thread object, but does not -// immediately start executing it. This gives the -// caller a chance to store it in a PT(Thread) object, -// if desired, before the thread gets a chance to -// terminate and destruct itself. -// -// Call start() to begin thread execution. -// -// The name should be unique for each thread (though -// this is not enforced, and not strictly required). -// The sync_name can be shared between multiple -// different threads; threads that run synchronously -// with each other should be given the same sync_name, -// for the benefit of PStats. -//////////////////////////////////////////////////////////////////// -INLINE Thread:: -Thread(const string &name, const string &sync_name) : - _name(name), - _sync_name(sync_name), - _impl(this) -{ - _started = false; - _pstats_index = -1; - _pstats_callback = NULL; - _pipeline_stage = 0; - -#ifdef DEBUG_THREADS - _blocked_on_mutex = NULL; -#endif -} - //////////////////////////////////////////////////////////////////// // Function: Thread::Copy Constructor // Access: Private diff --git a/panda/src/pipeline/thread.cxx b/panda/src/pipeline/thread.cxx index 75f2703f8e..a0ef82f9ec 100644 --- a/panda/src/pipeline/thread.cxx +++ b/panda/src/pipeline/thread.cxx @@ -21,6 +21,46 @@ Thread *Thread::_main_thread; Thread *Thread::_external_thread; TypeHandle Thread::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: Thread::Constructor +// Access: Protected +// Description: Creates a new Thread object, but does not +// immediately start executing it. This gives the +// caller a chance to store it in a PT(Thread) object, +// if desired, before the thread gets a chance to +// terminate and destruct itself. +// +// Call start() to begin thread execution. +// +// The name should be unique for each thread (though +// this is not enforced, and not strictly required). +// The sync_name can be shared between multiple +// different threads; threads that run synchronously +// with each other should be given the same sync_name, +// for the benefit of PStats. +//////////////////////////////////////////////////////////////////// +Thread:: +Thread(const string &name, const string &sync_name) : + _name(name), + _sync_name(sync_name), + _impl(this) +{ + _started = false; + _pstats_index = -1; + _pstats_callback = NULL; + _pipeline_stage = 0; + +#ifdef DEBUG_THREADS + _blocked_on_mutex = NULL; +#endif + +#if defined(HAVE_PYTHON) && !defined(SIMPLE_THREADS) + // Ensure that the Python threading system is initialized and ready + // to go. + PyEval_InitThreads(); +#endif +} + //////////////////////////////////////////////////////////////////// // Function: Thread::Destructor // Access: Published, Virtual @@ -239,7 +279,7 @@ call_python_func(PyObject *function, PyObject *args) { } #else // SIMPLE_THREADS - // With true threading enabled, we're better off using PyGILSTate. + // With true threading enabled, we're better off using PyGILState. PyGILState_STATE gstate; gstate = PyGILState_Ensure(); diff --git a/panda/src/pipeline/thread.h b/panda/src/pipeline/thread.h index c90a049e25..8ceaa42ff1 100644 --- a/panda/src/pipeline/thread.h +++ b/panda/src/pipeline/thread.h @@ -46,7 +46,7 @@ class MutexDebug; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA_PIPELINE Thread : public TypedReferenceCount { protected: - INLINE Thread(const string &name, const string &sync_name); + Thread(const string &name, const string &sync_name); PUBLISHED: virtual ~Thread();