Browse Source

fix some threading issues

David Rose 17 years ago
parent
commit
a29328046a

+ 11 - 7
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);

+ 46 - 0
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
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 0
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);
 

+ 1 - 1
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);

+ 0 - 6
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
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 34
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

+ 41 - 1
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();
     

+ 1 - 1
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();