aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules
diff options
context:
space:
mode:
authorPetr Viktorin <encukou@gmail.com>2025-04-28 15:48:48 +0200
committerGitHub <noreply@github.com>2025-04-28 15:48:48 +0200
commit4ebbfcf30e0e2d87ff6036d4d1de0f6f0ef7c46a (patch)
treebd04a48591c2bc6fc6df81c0c4ab8e27addeba4d /Modules
parent995b1a72f20e4b0bc44b6471d40c2c368d74efb1 (diff)
downloadcpython-4ebbfcf30e0e2d87ff6036d4d1de0f6f0ef7c46a.tar.gz
cpython-4ebbfcf30e0e2d87ff6036d4d1de0f6f0ef7c46a.zip
gh-87135: Raise PythonFinalizationError when joining a blocked daemon thread (gh-130402)
If `Py_IsFinalizing()` is true, non-daemon threads (other than the current one) are done, and daemon threads are prevented from running, so they cannot finalize themselves and become done. Joining them (without timeout) would block forever. Raise PythonFinalizationError instead of hanging. Raise even when a timeout is given, for consistency with trying to join your own thread. See gh-123940 for a use case: calling `join()` from `__del__`. This is ill-advised, but an exception should at least make it easier to diagnose.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_threadmodule.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 6967f7ef42f..9776a32755d 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -511,11 +511,21 @@ ThreadHandle_join(ThreadHandle *self, PyTime_t timeout_ns)
// To work around this, we set `thread_is_exiting` immediately before
// `thread_run` returns. We can be sure that we are not attempting to join
// ourselves if the handle's thread is about to exit.
- if (!_PyEvent_IsSet(&self->thread_is_exiting) &&
- ThreadHandle_ident(self) == PyThread_get_thread_ident_ex()) {
- // PyThread_join_thread() would deadlock or error out.
- PyErr_SetString(ThreadError, "Cannot join current thread");
- return -1;
+ if (!_PyEvent_IsSet(&self->thread_is_exiting)) {
+ if (ThreadHandle_ident(self) == PyThread_get_thread_ident_ex()) {
+ // PyThread_join_thread() would deadlock or error out.
+ PyErr_SetString(ThreadError, "Cannot join current thread");
+ return -1;
+ }
+ if (Py_IsFinalizing()) {
+ // gh-123940: On finalization, other threads are prevented from
+ // running Python code. They cannot finalize themselves,
+ // so join() would hang forever (or until timeout).
+ // We raise instead.
+ PyErr_SetString(PyExc_PythonFinalizationError,
+ "cannot join thread at interpreter shutdown");
+ return -1;
+ }
}
// Wait until the deadline for the thread to exit.