]> granicus.if.org Git - python/commitdiff
Issue #1402: PyInterpreterState_Clear() may still invoke user code
authorAmaury Forgeot d'Arc <amauryfa@gmail.com>
Thu, 29 Nov 2007 23:35:25 +0000 (23:35 +0000)
committerAmaury Forgeot d'Arc <amauryfa@gmail.com>
Thu, 29 Nov 2007 23:35:25 +0000 (23:35 +0000)
(in deallocation of running threads, for example), so the PyGILState_Release()
function must still be functional.
On the other hand, _PyGILState_Fini() only frees memory, and can be called later.

Backport candidate, but only after some experts comment on it.

Lib/test/test_threading.py
Python/pythonrun.c

index dced9cb17b71390cc89ad423cb7bc91b1a9d0b58..9e2653604c26e186b5186710fb6e826a329a21a9 100644 (file)
@@ -202,6 +202,40 @@ class ThreadTests(unittest.TestCase):
             t.join()
         # else the thread is still running, and we have no way to kill it
 
+    def test_finalize_runnning_thread(self):
+        # Issue 1402: the PyGILState_Ensure / _Release functions may be called
+        # very late on python exit: on deallocation of a running thread for
+        # example.
+        try:
+            import ctypes
+        except ImportError:
+            if verbose:
+                print("test_finalize_with_runnning_thread can't import ctypes")
+            return  # can't do anything
+
+        import subprocess
+        rc = subprocess.call([sys.executable, "-c", """if 1:
+            import ctypes, sys, time, thread
+
+            # Module globals are cleared before __del__ is run
+            # So we save the functions in class dict
+            class C:
+                ensure = ctypes.pythonapi.PyGILState_Ensure
+                release = ctypes.pythonapi.PyGILState_Release
+                def __del__(self):
+                    state = self.ensure()
+                    self.release(state)
+
+            def waitingThread():
+                x = C()
+                time.sleep(100)
+
+            thread.start_new_thread(waitingThread, ())
+            time.sleep(1) # be sure the other thread is waiting
+            sys.exit(42)
+            """])
+        self.assertEqual(rc, 42)
+
 class ThreadingExceptionTests(unittest.TestCase):
     # A RuntimeError should be raised if Thread.start() is called
     # multiple times.
index 96602ff15b5d32cffd96ca4b1ff292e49b8b06a0..adae679057b61fcbdce22dc6eed6b7206b4c4335 100644 (file)
@@ -437,11 +437,6 @@ Py_Finalize(void)
                _Py_PrintReferences(stderr);
 #endif /* Py_TRACE_REFS */
 
-       /* Cleanup auto-thread-state */
-#ifdef WITH_THREAD
-       _PyGILState_Fini();
-#endif /* WITH_THREAD */
-
        /* Clear interpreter state */
        PyInterpreterState_Clear(interp);
 
@@ -453,6 +448,11 @@ Py_Finalize(void)
 
        _PyExc_Fini();
 
+       /* Cleanup auto-thread-state */
+#ifdef WITH_THREAD
+       _PyGILState_Fini();
+#endif /* WITH_THREAD */
+
        /* Delete current thread */
        PyThreadState_Swap(NULL);
        PyInterpreterState_Delete(interp);