|
9 | 9 | import sys |
10 | 10 | _thread = import_module('_thread') |
11 | 11 | threading = import_module('threading') |
| 12 | +import _testcapi |
12 | 13 | import time |
13 | 14 | import unittest |
14 | 15 | import weakref |
@@ -754,6 +755,53 @@ def test_clear_threads_states_after_fork(self): |
754 | 755 | t.join() |
755 | 756 |
|
756 | 757 |
|
| 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 | + |
757 | 805 | class ThreadingExceptionTests(BaseTestCase): |
758 | 806 | # A RuntimeError should be raised if Thread.start() is called |
759 | 807 | # multiple times. |
|
0 commit comments