]> granicus.if.org Git - python/commitdiff
Issue #18808: Non-daemon threads are now automatically joined when a sub-interpreter...
authorAntoine Pitrou <solipsis@pitrou.net>
Sun, 25 Aug 2013 17:48:18 +0000 (19:48 +0200)
committerAntoine Pitrou <solipsis@pitrou.net>
Sun, 25 Aug 2013 17:48:18 +0000 (19:48 +0200)
Lib/test/test_threading.py
Misc/NEWS
Python/pythonrun.c

index ecf22fc7494c7a676ddb7af86fd5528f274c21af..362974965828909d7c631d4ccfe0f462a55b43b6 100644 (file)
@@ -9,6 +9,7 @@ import re
 import sys
 _thread = import_module('_thread')
 threading = import_module('threading')
+import _testcapi
 import time
 import unittest
 import weakref
@@ -754,6 +755,53 @@ class ThreadJoinOnShutdown(BaseTestCase):
             t.join()
 
 
+class SubinterpThreadingTests(BaseTestCase):
+
+    def test_threads_join(self):
+        # Non-daemon threads should be joined at subinterpreter shutdown
+        # (issue #18808)
+        r, w = os.pipe()
+        self.addCleanup(os.close, r)
+        self.addCleanup(os.close, w)
+        code = r"""if 1:
+            import os
+            import threading
+            import time
+
+            def f():
+                # Sleep a bit so that the thread is still running when
+                # Py_EndInterpreter is called.
+                time.sleep(0.05)
+                os.write(%d, b"x")
+            threading.Thread(target=f).start()
+            """ % (w,)
+        ret = _testcapi.run_in_subinterp(code)
+        self.assertEqual(ret, 0)
+        # The thread was joined properly.
+        self.assertEqual(os.read(r, 1), b"x")
+
+    def test_daemon_threads_fatal_error(self):
+        subinterp_code = r"""if 1:
+            import os
+            import threading
+            import time
+
+            def f():
+                # Make sure the daemon thread is still running when
+                # Py_EndInterpreter is called.
+                time.sleep(10)
+            threading.Thread(target=f, daemon=True).start()
+            """
+        script = r"""if 1:
+            import _testcapi
+
+            _testcapi.run_in_subinterp(%r)
+            """ % (subinterp_code,)
+        rc, out, err = assert_python_failure("-c", script)
+        self.assertIn("Fatal Python error: Py_EndInterpreter: "
+                      "not the last thread", err.decode())
+
+
 class ThreadingExceptionTests(BaseTestCase):
     # A RuntimeError should be raised if Thread.start() is called
     # multiple times.
index b923109b8cea47d724f9ecfba45d72747fbaa2e4..90f15be68a7cd836ae4bacbb0dd85a1f93cec265 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@ Projected Release date: 2013-09-08
 Core and Builtins
 -----------------
 
+- Issue #18808: Non-daemon threads are now automatically joined when
+  a sub-interpreter is shutdown (it would previously dump a fatal error).
+
 - Remove supporting for compiling on systems without getcwd().
 
 - Issue #18774: Remove last bits of GNU PTH thread code and thread_pth.h.
index b0bc54964719fa256ab467e161958d6d76b5d99b..37dc3b8dc88bbedbb90aae44a207df1feb8904a0 100644 (file)
@@ -789,6 +789,9 @@ Py_EndInterpreter(PyThreadState *tstate)
         Py_FatalError("Py_EndInterpreter: thread is not current");
     if (tstate->frame != NULL)
         Py_FatalError("Py_EndInterpreter: thread still has a frame");
+
+    wait_for_thread_shutdown();
+
     if (tstate != interp->tstate_head || tstate->next != NULL)
         Py_FatalError("Py_EndInterpreter: not the last thread");