From 19b7d6c48fa5d9f0773eae39d19d55841a382cfd Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Fri, 18 Apr 2025 22:12:40 +0300 Subject: [PATCH 1/4] Add test for native thread ID after fork --- Lib/test/test_threading.py | 19 +++++++++++++++++++ Lib/threading.py | 2 ++ 2 files changed, 21 insertions(+) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index fa666608263e27..a7fac6e28ecd20 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1276,6 +1276,25 @@ def do_flush(*args, **kwargs): ''') assert_python_ok("-c", script) + @skip_unless_reliable_fork + def test_native_id_after_fork(self): + script = """if True: + import threading + import os + + print(threading.current_thread().native_id, flush=True) + assert threading.current_thread().native_id == threading.get_native_id() + if os.fork() == 0: + print(threading.current_thread().native_id, flush=True) + assert threading.current_thread().native_id == threading.get_native_id() + """ + rc, out, err = assert_python_ok('-c', script) + self.assertEqual(rc, 0) + self.assertEqual(err, b"") + native_ids = out.strip().splitlines() + self.assertEqual(len(native_ids), 2) + self.assertNotEqual(native_ids[0], native_ids[1]) + class ThreadJoinOnShutdown(BaseTestCase): def _run_and_join(self, script): diff --git a/Lib/threading.py b/Lib/threading.py index c4cc4dd2b00aa8..6b6be119ffa437 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -951,6 +951,8 @@ def _after_fork(self, new_ident=None): # This thread is alive. self._ident = new_ident assert self._handle.ident == new_ident + if _HAVE_THREAD_NATIVE_ID: + self._set_native_id() else: # Otherwise, the thread is dead, Jim. _PyThread_AfterFork() # already marked our handle done. From 011573835f4a1b2aa812cc525426d7c5b5a36d9a Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 19 Apr 2025 17:07:46 +0300 Subject: [PATCH 2/4] Enhance test for native thread ID after fork to validate parent thread ID consistency --- Lib/test/test_threading.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index a7fac6e28ecd20..bea6aed2461c73 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1282,11 +1282,15 @@ def test_native_id_after_fork(self): import threading import os - print(threading.current_thread().native_id, flush=True) - assert threading.current_thread().native_id == threading.get_native_id() + parent_thread_native_id = threading.current_thread().native_id + print(parent_thread_native_id, flush=True) + assert parent_thread_native_id == threading.get_native_id() if os.fork() == 0: print(threading.current_thread().native_id, flush=True) assert threading.current_thread().native_id == threading.get_native_id() + else: + assert parent_thread_native_id == threading.current_thread().native_id + assert parent_thread_native_id == threading.get_native_id() """ rc, out, err = assert_python_ok('-c', script) self.assertEqual(rc, 0) From 6ebd095e1c5367cd1a9f7c4f30698b5f54196c4b Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Sat, 19 Apr 2025 17:16:58 +0300 Subject: [PATCH 3/4] Add blurb entry --- .../2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst new file mode 100644 index 00000000000000..c69ce5efdedcca --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-19-17-16-46.gh-issue-132542.7T_TY_.rst @@ -0,0 +1,2 @@ +Update :attr:`Thread.native_id ` after +:manpage:`fork(2)` to ensure accuracy. Patch by Noam Cohen. From a7e5c51df735b474ea54f09cafa3dc51b58795f5 Mon Sep 17 00:00:00 2001 From: Noam Cohen Date: Tue, 20 May 2025 18:34:02 +0300 Subject: [PATCH 4/4] wait for child process in test --- Lib/test/test_threading.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index bea6aed2461c73..9fc3b4a23bed3d 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -1281,16 +1281,21 @@ def test_native_id_after_fork(self): script = """if True: import threading import os + from test import support parent_thread_native_id = threading.current_thread().native_id print(parent_thread_native_id, flush=True) assert parent_thread_native_id == threading.get_native_id() - if os.fork() == 0: + childpid = os.fork() + if childpid == 0: print(threading.current_thread().native_id, flush=True) assert threading.current_thread().native_id == threading.get_native_id() else: - assert parent_thread_native_id == threading.current_thread().native_id - assert parent_thread_native_id == threading.get_native_id() + try: + assert parent_thread_native_id == threading.current_thread().native_id + assert parent_thread_native_id == threading.get_native_id() + finally: + support.wait_process(childpid, exitcode=0) """ rc, out, err = assert_python_ok('-c', script) self.assertEqual(rc, 0)