Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions Doc/library/threading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.
Expand Down
9 changes: 0 additions & 9 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
---

Expand Down
42 changes: 19 additions & 23 deletions Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
5 changes: 0 additions & 5 deletions Lib/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Allow again to spawn daemon threads in subinterpreters (revert change which
denied them).
24 changes: 0 additions & 24 deletions Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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 */
};

Expand Down
22 changes: 0 additions & 22 deletions Modules/clinic/_threadmodule.c.h

This file was deleted.