From 145cf80b799f1ecd67e00e11f214ec649148b01d Mon Sep 17 00:00:00 2001 From: lazerg Date: Thu, 24 Sep 2026 19:57:33 +0500 Subject: [PATCH] gh-158090: Fix hang at shutdown when a daemon thread resets the GIL drop request --- .../2026-09-24-14-57-33.gh-issue-158090.0jWUTp.rst | 2 ++ Python/ceval_gil.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-14-57-33.gh-issue-158090.0jWUTp.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-14-57-33.gh-issue-158090.0jWUTp.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-14-57-33.gh-issue-158090.0jWUTp.rst new file mode 100644 index 000000000000000..d892b90c537e1de --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-09-24-14-57-33.gh-issue-158090.0jWUTp.rst @@ -0,0 +1,2 @@ +Fix a race condition at interpreter shutdown where a daemon thread waiting +for the GIL could leave the main thread blocked forever in ``drop_gil()``. diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 49b2ede4ed3e60f..891711e170a8c6c 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -343,7 +343,6 @@ take_gil(PyThreadState *tstate) PyThreadState *holder_tstate = (PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder); if (_PyThreadState_MustExit(tstate)) { - MUTEX_UNLOCK(gil->mutex); // gh-96387: If the loop requested a drop request in a previous // iteration, reset the request. Otherwise, drop_gil() can // block forever waiting for the thread which exited. Drop @@ -353,6 +352,7 @@ take_gil(PyThreadState *tstate) if (drop_requested) { _Py_unset_eval_breaker_bit(holder_tstate, _PY_GIL_DROP_REQUEST_BIT); } + MUTEX_UNLOCK(gil->mutex); // gh-87135: hang the thread as *thread_exit() is not a safe // API. It lacks stack unwind and local variable destruction. _PyThreadState_HangThread(tstate);