bpo-40234: Revert "bpo-37266: Daemon threads are now denied in subinterpreters (GH-14049)" (GH-19456)
This reverts commit 066e5b1a91
.
This commit is contained in:
parent
909b87d2bb
commit
14d5331eb5
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
import time
|
||||
|
||||
channel = open({w}, "w", closefd=False)
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Allow again to spawn daemon threads in subinterpreters (revert change which
|
||||
denied them).
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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]*/
|
Loading…
Reference in New Issue