Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7eaf3f7

Browse files
committed
Issue #18808: Non-daemon threads are now automatically joined when a sub-interpreter is shutdown (it would previously dump a fatal error).
1 parent 0bb766b commit 7eaf3f7

3 files changed

Lines changed: 54 additions & 0 deletions

File tree

Lib/test/test_threading.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import sys
1010
_thread = import_module('_thread')
1111
threading = import_module('threading')
12+
import _testcapi
1213
import time
1314
import unittest
1415
import weakref
@@ -754,6 +755,53 @@ def test_clear_threads_states_after_fork(self):
754755
t.join()
755756

756757

758+
class SubinterpThreadingTests(BaseTestCase):
759+
760+
def test_threads_join(self):
761+
# Non-daemon threads should be joined at subinterpreter shutdown
762+
# (issue #18808)
763+
r, w = os.pipe()
764+
self.addCleanup(os.close, r)
765+
self.addCleanup(os.close, w)
766+
code = r"""if 1:
767+
import os
768+
import threading
769+
import time
770+
771+
def f():
772+
# Sleep a bit so that the thread is still running when
773+
# Py_EndInterpreter is called.
774+
time.sleep(0.05)
775+
os.write(%d, b"x")
776+
threading.Thread(target=f).start()
777+
""" % (w,)
778+
ret = _testcapi.run_in_subinterp(code)
779+
self.assertEqual(ret, 0)
780+
# The thread was joined properly.
781+
self.assertEqual(os.read(r, 1), b"x")
782+
783+
def test_daemon_threads_fatal_error(self):
784+
subinterp_code = r"""if 1:
785+
import os
786+
import threading
787+
import time
788+
789+
def f():
790+
# Make sure the daemon thread is still running when
791+
# Py_EndInterpreter is called.
792+
time.sleep(10)
793+
threading.Thread(target=f, daemon=True).start()
794+
"""
795+
script = r"""if 1:
796+
import _testcapi
797+
798+
_testcapi.run_in_subinterp(%r)
799+
""" % (subinterp_code,)
800+
rc, out, err = assert_python_failure("-c", script)
801+
self.assertIn("Fatal Python error: Py_EndInterpreter: "
802+
"not the last thread", err.decode())
803+
804+
757805
class ThreadingExceptionTests(BaseTestCase):
758806
# A RuntimeError should be raised if Thread.start() is called
759807
# multiple times.

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Projected Release date: 2013-09-08
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #18808: Non-daemon threads are now automatically joined when
14+
a sub-interpreter is shutdown (it would previously dump a fatal error).
15+
1316
- Remove supporting for compiling on systems without getcwd().
1417

1518
- Issue #18774: Remove last bits of GNU PTH thread code and thread_pth.h.

Python/pythonrun.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,9 @@ Py_EndInterpreter(PyThreadState *tstate)
789789
Py_FatalError("Py_EndInterpreter: thread is not current");
790790
if (tstate->frame != NULL)
791791
Py_FatalError("Py_EndInterpreter: thread still has a frame");
792+
793+
wait_for_thread_shutdown();
794+
792795
if (tstate != interp->tstate_head || tstate->next != NULL)
793796
Py_FatalError("Py_EndInterpreter: not the last thread");
794797

0 commit comments

Comments
 (0)