Browse Source

change order of thread cleanup to avoid python crash

David Rose 18 years ago
parent
commit
3e4e3248e7

+ 6 - 4
panda/src/pipeline/contextSwitch.c

@@ -45,8 +45,9 @@ init_thread_context(struct ThreadContext *context,
   makecontext(&context->_ucontext, (void (*)())&begin_context, 2, thread_func, data);
   makecontext(&context->_ucontext, (void (*)())&begin_context, 2, thread_func, data);
 }
 }
 
 
-void save_thread_context(struct ThreadContext *context,
-                         ContextFunction *next_context, void *data) {
+void
+save_thread_context(struct ThreadContext *context,
+                    ContextFunction *next_context, void *data) {
   /* getcontext requires us to use a volatile auto variable to
   /* getcontext requires us to use a volatile auto variable to
      differentiate between pass 1 (immediate return) and pass 2
      differentiate between pass 1 (immediate return) and pass 2
      (return from setcontext). */
      (return from setcontext). */
@@ -297,8 +298,9 @@ init_thread_context(struct ThreadContext *context,
   setup_context_1();
   setup_context_1();
 }  
 }  
 
 
-void save_thread_context(struct ThreadContext *context,
-                         ContextFunction *next_context, void *data) {
+void
+save_thread_context(struct ThreadContext *context,
+                    ContextFunction *next_context, void *data) {
   if (cs_setjmp(context->_jmp_context) != 0) {
   if (cs_setjmp(context->_jmp_context) != 0) {
     /* We have just returned from longjmp.  In this case, return from
     /* We have just returned from longjmp.  In this case, return from
        the function.  The stack is still good. */
        the function.  The stack is still good. */

+ 4 - 3
panda/src/pipeline/pythonThread.cxx

@@ -33,13 +33,14 @@ PythonThread(PyObject *function, PyObject *args,
              const string &name, const string &sync_name) :
              const string &name, const string &sync_name) :
   Thread(name, sync_name)
   Thread(name, sync_name)
 {
 {
+  _function = function;
+  Py_INCREF(_function);
+  _args = NULL;
   _result = NULL;
   _result = NULL;
 
 
-  _function = function;
   if (!PyCallable_Check(_function)) {
   if (!PyCallable_Check(_function)) {
     nassert_raise("Invalid function passed to PythonThread constructor");
     nassert_raise("Invalid function passed to PythonThread constructor");
   }
   }
-  Py_INCREF(_function);
 
 
   if (args == Py_None) {
   if (args == Py_None) {
     // None means no arguments; create an empty tuple.
     // None means no arguments; create an empty tuple.
@@ -113,7 +114,7 @@ thread_main() {
   // thread state per OS-level thread, which is not true in the case
   // thread state per OS-level thread, which is not true in the case
   // of SIMPLE_THREADS.
   // of SIMPLE_THREADS.
 
 
-  PyThreadState *orig_thread_state = PyThreadState_Swap(NULL);
+  PyThreadState *orig_thread_state = PyThreadState_Get();
   PyInterpreterState *istate = orig_thread_state->interp;
   PyInterpreterState *istate = orig_thread_state->interp;
   PyThreadState *new_thread_state = PyThreadState_New(istate);
   PyThreadState *new_thread_state = PyThreadState_New(istate);
   PyThreadState_Swap(new_thread_state);
   PyThreadState_Swap(new_thread_state);

+ 9 - 6
panda/src/pipeline/threadSimpleManager.cxx

@@ -200,6 +200,14 @@ preempt(ThreadSimpleImpl *thread) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ThreadSimpleManager::
 void ThreadSimpleManager::
 next_context() {
 next_context() {
+  // Delete any threads that need it.  We can't delete the current
+  // thread, though.
+  while (!_finished.empty() && _finished.front() != _current_thread) {
+    ThreadSimpleImpl *finished_thread = _finished.front();
+    _finished.pop_front();
+    unref_delete(finished_thread->_parent_obj);
+  }
+
   // Mark the current thread's resume point.
   // Mark the current thread's resume point.
 
 
 #ifdef HAVE_PYTHON
 #ifdef HAVE_PYTHON
@@ -268,6 +276,7 @@ prepare_for_exit() {
 
 
   next_context();
   next_context();
 
 
+  // Delete any remaining threads.
   while (!_finished.empty() && _finished.front() != _current_thread) {
   while (!_finished.empty() && _finished.front() != _current_thread) {
     ThreadSimpleImpl *finished_thread = _finished.front();
     ThreadSimpleImpl *finished_thread = _finished.front();
     _finished.pop_front();
     _finished.pop_front();
@@ -410,12 +419,6 @@ st_choose_next_context(void *data) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void ThreadSimpleManager::
 void ThreadSimpleManager::
 choose_next_context() {
 choose_next_context() {
-  while (!_finished.empty() && _finished.front() != _current_thread) {
-    ThreadSimpleImpl *finished_thread = _finished.front();
-    _finished.pop_front();
-    unref_delete(finished_thread->_parent_obj);
-  }
-
   _current_thread = NULL;
   _current_thread = NULL;
 
 
   double now = get_current_time();
   double now = get_current_time();