diff options
-rw-r--r-- | Doc/library/threading.rst | 8 | ||||
-rw-r--r-- | Doc/whatsnew/3.9.rst | 9 | ||||
-rw-r--r-- | Lib/test/test_threading.py | 42 | ||||
-rw-r--r-- | Lib/threading.py | 5 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2020-04-10-16-13-47.bpo-40234.tar4d_.rst | 2 | ||||
-rw-r--r-- | Modules/_threadmodule.c | 24 | ||||
-rw-r--r-- | Modules/clinic/_threadmodule.c.h | 22 |
7 files changed, 21 insertions, 91 deletions
diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst index 1e90294..3a446ad 100644 --- a/Doc/library/threading.rst +++ b/Doc/library/threading.rst @@ -280,8 +280,6 @@ since it is impossible to detect the termination of alien threads. base class constructor (``Thread.__init__()``) before doing anything else to the thread. - Daemon threads must not be used in subinterpreters. - .. versionchanged:: 3.3 Added the *daemon* argument. @@ -296,12 +294,6 @@ since it is impossible to detect the termination of alien threads. This method will raise a :exc:`RuntimeError` if called more than once on the same thread object. - Raise a :exc:`RuntimeError` if the thread is a daemon thread and the - method is called from a subinterpreter. - - .. versionchanged:: 3.9 - In a subinterpreter, spawning a daemon thread now raises an exception. - .. method:: run() Method representing the thread's activity. diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 6cd80ce..020a869 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -369,15 +369,6 @@ The :mod:`socket` module now exports the :data:`~socket.CAN_RAW_JOIN_FILTERS` constant on Linux 4.1 and greater. (Contributed by Stefan Tatschner and Zackery Spytz in :issue:`25780`.) -threading ---------- - -In a subinterpreter, spawning a daemon thread now raises a :exc:`RuntimeError`. Daemon -threads were never supported in subinterpreters. Previously, the subinterpreter -finalization crashed with a Python fatal error if a daemon thread was still -running. -(Contributed by Victor Stinner in :issue:`37266`.) - sys --- diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 8a4efd6..81e5f70 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1022,32 +1022,28 @@ class SubinterpThreadingTests(BaseTestCase): # The thread was joined properly. self.assertEqual(os.read(r, 1), b"x") - def test_daemon_thread(self): - r, w = self.pipe() - code = textwrap.dedent(f""" + @cpython_only + def test_daemon_threads_fatal_error(self): + subinterp_code = f"""if 1: + import os import threading - import sys - - channel = open({w}, "w", closefd=False) - - def func(): - pass + import time - 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) + def f(): + # Make sure the daemon thread is still running when + # Py_EndInterpreter is called. + time.sleep({test.support.SHORT_TIMEOUT}) + threading.Thread(target=f, daemon=True).start() + """ + script = r"""if 1: + import _testcapi - msg = os.read(r, 100).decode().rstrip() - self.assertEqual("ok: daemon thread are not supported " - "in subinterpreters", msg) + _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()) class ThreadingExceptionTests(BaseTestCase): diff --git a/Lib/threading.py b/Lib/threading.py index 5424db3..ab29db7 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -35,7 +35,6 @@ _start_new_thread = _thread.start_new_thread _allocate_lock = _thread.allocate_lock _set_sentinel = _thread._set_sentinel get_ident = _thread.get_ident -_is_main_interpreter = _thread._is_main_interpreter try: get_native_id = _thread.get_native_id _HAVE_THREAD_NATIVE_ID = True @@ -865,10 +864,6 @@ class Thread: if self._started.is_set(): raise RuntimeError("threads can only be started once") - if self.daemon and not _is_main_interpreter(): - raise RuntimeError("daemon thread are not supported " - "in subinterpreters") - with _active_limbo_lock: _limbo[self] = self try: diff --git a/Misc/NEWS.d/next/Library/2020-04-10-16-13-47.bpo-40234.tar4d_.rst b/Misc/NEWS.d/next/Library/2020-04-10-16-13-47.bpo-40234.tar4d_.rst new file mode 100644 index 0000000..ed7a9f3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-04-10-16-13-47.bpo-40234.tar4d_.rst @@ -0,0 +1,2 @@ +Allow again to spawn daemon threads in subinterpreters (revert change which +denied them). diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index addef3e..e2bb14e 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -8,14 +8,6 @@ #include "structmember.h" /* offsetof */ #include "pythread.h" -#include "clinic/_threadmodule.c.h" - -/*[clinic input] -module _thread -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=be8dbe5cc4b16df7]*/ - - static PyObject *ThreadError; static PyObject *str_dict; @@ -1493,21 +1485,6 @@ PyDoc_STRVAR(excepthook_doc, \n\ Handle uncaught Thread.run() exception."); -/*[clinic input] -_thread._is_main_interpreter - -Return True if the current interpreter is the main Python interpreter. -[clinic start generated code]*/ - -static PyObject * -_thread__is_main_interpreter_impl(PyObject *module) -/*[clinic end generated code: output=7dd82e1728339adc input=cc1eb00fd4598915]*/ -{ - PyThreadState *tstate = _PyThreadState_GET(); - int is_main = _Py_IsMainInterpreter(tstate); - return PyBool_FromLong(is_main); -} - static PyMethodDef thread_methods[] = { {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, METH_VARARGS, start_new_doc}, @@ -1537,7 +1514,6 @@ static PyMethodDef thread_methods[] = { METH_NOARGS, _set_sentinel_doc}, {"_excepthook", thread_excepthook, METH_O, excepthook_doc}, - _THREAD__IS_MAIN_INTERPRETER_METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/clinic/_threadmodule.c.h b/Modules/clinic/_threadmodule.c.h deleted file mode 100644 index 07ea08b..0000000 --- a/Modules/clinic/_threadmodule.c.h +++ /dev/null @@ -1,22 +0,0 @@ -/*[clinic input] -preserve -[clinic start generated code]*/ - -PyDoc_STRVAR(_thread__is_main_interpreter__doc__, -"_is_main_interpreter($module, /)\n" -"--\n" -"\n" -"Return True if the current interpreter is the main Python interpreter."); - -#define _THREAD__IS_MAIN_INTERPRETER_METHODDEF \ - {"_is_main_interpreter", (PyCFunction)_thread__is_main_interpreter, METH_NOARGS, _thread__is_main_interpreter__doc__}, - -static PyObject * -_thread__is_main_interpreter_impl(PyObject *module); - -static PyObject * -_thread__is_main_interpreter(PyObject *module, PyObject *Py_UNUSED(ignored)) -{ - return _thread__is_main_interpreter_impl(module); -} -/*[clinic end generated code: output=505840d1b9101789 input=a9049054013a1b77]*/ |