diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-06-14 18:55:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-14 18:55:22 +0200 |
commit | 066e5b1a917ec2134e8997d2cadd815724314252 (patch) | |
tree | 963b0b6d7d2ae0c580aa48da0d1423930bf2a32d /Lib/test/test_threading.py | |
parent | 212646cae6b7c4ddc8d98c8b9b6d39a5f259e864 (diff) | |
download | cpython-git-066e5b1a917ec2134e8997d2cadd815724314252.tar.gz |
bpo-37266: Daemon threads are now denied in subinterpreters (GH-14049)
In a subinterpreter, spawning a daemon thread now raises an
exception. Daemon threads were never supported in subinterpreters.
Previously, the subinterpreter finalization crashed with a Pyton
fatal error if a daemon thread was still running.
* Add _thread._is_main_interpreter()
* threading.Thread.start() now raises RuntimeError if the thread is a
daemon thread and the method is called from a subinterpreter.
* The _thread module now uses Argument Clinic for the new function.
* Use textwrap.dedent() in test_threading.SubinterpThreadingTests
Diffstat (limited to 'Lib/test/test_threading.py')
-rw-r--r-- | Lib/test/test_threading.py | 66 |
1 files changed, 37 insertions, 29 deletions
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 0a0a62bdf9..a04d496001 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -17,6 +17,7 @@ import weakref import os import subprocess import signal +import textwrap from test import lock_tests from test import support @@ -928,14 +929,19 @@ class ThreadJoinOnShutdown(BaseTestCase): class SubinterpThreadingTests(BaseTestCase): + def pipe(self): + r, w = os.pipe() + self.addCleanup(os.close, r) + self.addCleanup(os.close, w) + if hasattr(os, 'set_blocking'): + os.set_blocking(r, False) + return (r, w) 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: + r, w = self.pipe() + code = textwrap.dedent(r""" import os import random import threading @@ -953,7 +959,7 @@ class SubinterpThreadingTests(BaseTestCase): threading.Thread(target=f).start() random_sleep() - """ % (w,) + """ % (w,)) ret = test.support.run_in_subinterp(code) self.assertEqual(ret, 0) # The thread was joined properly. @@ -964,10 +970,8 @@ class SubinterpThreadingTests(BaseTestCase): # Python code returned but before the thread state is deleted. # To achieve this, we register a thread-local object which sleeps # a bit when deallocated. - r, w = os.pipe() - self.addCleanup(os.close, r) - self.addCleanup(os.close, w) - code = r"""if 1: + r, w = self.pipe() + code = textwrap.dedent(r""" import os import random import threading @@ -992,34 +996,38 @@ class SubinterpThreadingTests(BaseTestCase): threading.Thread(target=f).start() random_sleep() - """ % (w,) + """ % (w,)) ret = test.support.run_in_subinterp(code) self.assertEqual(ret, 0) # The thread was joined properly. self.assertEqual(os.read(r, 1), b"x") - @cpython_only - def test_daemon_threads_fatal_error(self): - subinterp_code = r"""if 1: - import os + def test_daemon_thread(self): + r, w = self.pipe() + code = textwrap.dedent(f""" import threading - import time + import sys - 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 + channel = open({w}, "w", closefd=False) + + def func(): + pass + + thread = threading.Thread(target=func, daemon=True) + try: + thread.start() + except RuntimeError as exc: + print("ok: %s" % exc, file=channel, flush=True) + else: + thread.join() + print("fail: RuntimeError not raised", file=channel, flush=True) + """) + ret = test.support.run_in_subinterp(code) + self.assertEqual(ret, 0) - _testcapi.run_in_subinterp(%r) - """ % (subinterp_code,) - with test.support.SuppressCrashReport(): - rc, out, err = assert_python_failure("-c", script) - self.assertIn("Fatal Python error: Py_EndInterpreter: " - "not the last thread", err.decode()) + msg = os.read(r, 100).decode().rstrip() + self.assertEqual("ok: daemon thread are not supported " + "in subinterpreters", msg) class ThreadingExceptionTests(BaseTestCase): |