[Python-checkins] bpo-40234: Revert "bpo-37266: Daemon threads are now denied in subinterpreters (GH-14049)" (GH-19456)

Victor Stinner webhook-mailer at python.org
Sun Apr 12 17:45:21 EDT 2020


https://github.com/python/cpython/commit/14d5331eb5e6c38be12bad421bd59ad0fac9e448
commit: 14d5331eb5e6c38be12bad421bd59ad0fac9e448
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-04-12T23:45:09+02:00
summary:

bpo-40234: Revert "bpo-37266: Daemon threads are now denied in subinterpreters (GH-14049)" (GH-19456)

This reverts commit 066e5b1a917ec2134e8997d2cadd815724314252.

files:
A Misc/NEWS.d/next/Library/2020-04-10-16-13-47.bpo-40234.tar4d_.rst
D Modules/clinic/_threadmodule.c.h
M Doc/library/threading.rst
M Doc/whatsnew/3.9.rst
M Lib/test/test_threading.py
M Lib/threading.py
M Modules/_threadmodule.c

diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
index 1e90294142796..3a446adfac8c5 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 6cd80ce8e4ff9..020a86958f7af 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 8a4efd647096a..81e5f70d6d6ae 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -1022,32 +1022,28 @@ def f():
         # 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 5424db3dabc44..ab29db77a747a 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -35,7 +35,6 @@
 _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 @@ def start(self):
         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 0000000000000..ed7a9f355dbac
--- /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 addef3ee54e0f..e2bb14ec728b4 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 07ea08b1750d5..0000000000000
--- 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]*/



More information about the Python-checkins mailing list