]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-137017: Ensure `Thread.is_alive()` only returns False after the underlying...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 15 Sep 2025 13:28:05 +0000 (15:28 +0200)
committerGitHub <noreply@github.com>
Mon, 15 Sep 2025 13:28:05 +0000 (14:28 +0100)
(cherry picked from commit aa9ceb17215af21ed6618d6f7ccb5bf57ca57101)

Co-authored-by: Abdul <abdulrasheedibrahim47@gmail.com>
Co-authored-by: Sam Gross <colesbury@gmail.com>
Misc/NEWS.d/next/Library/2025-08-01-23-11-25.gh-issue-137017.0yGcNc.rst [new file with mode: 0644]
Modules/_threadmodule.c

diff --git a/Misc/NEWS.d/next/Library/2025-08-01-23-11-25.gh-issue-137017.0yGcNc.rst b/Misc/NEWS.d/next/Library/2025-08-01-23-11-25.gh-issue-137017.0yGcNc.rst
new file mode 100644 (file)
index 0000000..7c2c013
--- /dev/null
@@ -0,0 +1,3 @@
+Fix :obj:`threading.Thread.is_alive` to remain ``True`` until the underlying OS
+thread is fully cleaned up. This avoids false negatives in edge cases
+involving thread monitoring or premature :obj:`threading.Thread.is_alive` calls.
index 3f9e0a948568ca34014b3c95cce4dbb634b71ccf..bc9433afe41ef100e81b26937da5b4c02b0893c7 100644 (file)
@@ -453,8 +453,9 @@ start_failed:
 }
 
 static int
-join_thread(ThreadHandle *handle)
+join_thread(void *arg)
 {
+    ThreadHandle *handle = (ThreadHandle*)arg;
     assert(get_thread_handle_state(handle) == THREAD_HANDLE_RUNNING);
     PyThread_handle_t os_handle;
     if (ThreadHandle_get_os_handle(handle, &os_handle)) {
@@ -528,8 +529,7 @@ ThreadHandle_join(ThreadHandle *self, PyTime_t timeout_ns)
         }
     }
 
-    if (_PyOnceFlag_CallOnce(&self->once, (_Py_once_fn_t *)join_thread,
-                             self) == -1) {
+    if (_PyOnceFlag_CallOnce(&self->once, join_thread, self) == -1) {
         return -1;
     }
     assert(get_thread_handle_state(self) == THREAD_HANDLE_DONE);
@@ -657,6 +657,9 @@ PyThreadHandleObject_is_done(PyThreadHandleObject *self,
                              PyObject *Py_UNUSED(ignored))
 {
     if (_PyEvent_IsSet(&self->handle->thread_is_exiting)) {
+        if (_PyOnceFlag_CallOnce(&self->handle->once, join_thread, self->handle) == -1) {
+            return NULL;
+        }
         Py_RETURN_TRUE;
     }
     else {