]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-134381: Fix RuntimeError when starting not-yet started Thread after fork...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 23 May 2025 19:45:51 +0000 (21:45 +0200)
committerGitHub <noreply@github.com>
Fri, 23 May 2025 19:45:51 +0000 (19:45 +0000)
(cherry picked from commit 9a2346df861f26d5f8d054ad2f9c37134dee3822)

Co-authored-by: Jiucheng(Oliver) <git.jiucheng@gmail.com>
Lib/test/_test_multiprocessing.py
Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst [new file with mode: 0644]
Modules/_threadmodule.c

index 9e3330e40ffaab25b5ce7ec4d79536043cffcfd5..0b8de96f1b0c9657fb02179b390a7383765ca417 100644 (file)
@@ -6494,6 +6494,28 @@ class MiscTestCase(unittest.TestCase):
         self.assertEqual("332833500", out.decode('utf-8').strip())
         self.assertFalse(err, msg=err.decode('utf-8'))
 
+    def test_forked_thread_not_started(self):
+        # gh-134381: Ensure that a thread that has not been started yet in
+        # the parent process can be started within a forked child process.
+
+        if multiprocessing.get_start_method() != "fork":
+            self.skipTest("fork specific test")
+
+        q = multiprocessing.Queue()
+        t = threading.Thread(target=lambda: q.put("done"), daemon=True)
+
+        def child():
+            t.start()
+            t.join()
+
+        p = multiprocessing.Process(target=child)
+        p.start()
+        p.join(support.SHORT_TIMEOUT)
+
+        self.assertEqual(p.exitcode, 0)
+        self.assertEqual(q.get_nowait(), "done")
+        close_queue(q)
+
 
 #
 # Mixins
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-22-14-48-19.gh-issue-134381.2BXhth.rst
new file mode 100644 (file)
index 0000000..aa89002
--- /dev/null
@@ -0,0 +1 @@
+Fix :exc:`RuntimeError` when using a not-started :class:`threading.Thread` after calling :func:`os.fork`
index 2853f3d26773d0cc2edcb356b329f461aa05b4e6..52bb45f1891ac398c75b4fcffdcee90333321d66 100644 (file)
@@ -262,6 +262,12 @@ _PyThread_AfterFork(struct _pythread_runtime_state *state)
             continue;
         }
 
+        // Keep handles for threads that have not been started yet. They are
+        // safe to start in the child process.
+        if (handle->state == THREAD_HANDLE_NOT_STARTED) {
+            continue;
+        }
+
         // Mark all threads as done. Any attempts to join or detach the
         // underlying OS thread (if any) could crash. We are the only thread;
         // it's safe to set this non-atomically.