Skip to content

Commit a9f9687

Browse files
authored
bpo-40094: Enhance threading tests (GH-19260)
* Rewrite test_thread.test_forkinthread() to use support.wait_process() and wait for the child process in the main thread, not in the spawned thread. * test_threading now uses support.wait_process() and checks the child process exit code to detect crashes.
1 parent 27c6231 commit a9f9687

File tree

2 files changed

+39
-31
lines changed

2 files changed

+39
-31
lines changed

Lib/test/test_thread.py

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -225,30 +225,31 @@ def setUp(self):
225225
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
226226
@support.reap_threads
227227
def test_forkinthread(self):
228-
status = "not set"
228+
pid = None
229229

230-
def thread1():
231-
nonlocal status
230+
def fork_thread(read_fd, write_fd):
231+
nonlocal pid
232232

233233
# fork in a thread
234234
pid = os.fork()
235-
if pid == 0:
236-
# child
237-
try:
238-
os.close(self.read_fd)
239-
os.write(self.write_fd, b"OK")
240-
finally:
241-
os._exit(0)
242-
else:
243-
# parent
244-
os.close(self.write_fd)
245-
pid, status = os.waitpid(pid, 0)
235+
if pid:
236+
# parent process
237+
return
238+
239+
# child process
240+
try:
241+
os.close(read_fd)
242+
os.write(write_fd, b"OK")
243+
finally:
244+
os._exit(0)
246245

247246
with support.wait_threads_exit():
248-
thread.start_new_thread(thread1, ())
249-
self.assertEqual(os.read(self.read_fd, 2), b"OK",
250-
"Unable to fork() in thread")
251-
self.assertEqual(status, 0)
247+
thread.start_new_thread(fork_thread, (self.read_fd, self.write_fd))
248+
self.assertEqual(os.read(self.read_fd, 2), b"OK")
249+
os.close(self.write_fd)
250+
251+
self.assertIsNotNone(pid)
252+
support.wait_process(pid, exitcode=0)
252253

253254
def tearDown(self):
254255
try:

Lib/test/test_threading.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -485,9 +485,7 @@ def test_is_alive_after_fork(self):
485485
else:
486486
t.join()
487487

488-
pid, status = os.waitpid(pid, 0)
489-
self.assertTrue(os.WIFEXITED(status))
490-
self.assertEqual(10, os.WEXITSTATUS(status))
488+
support.wait_process(pid, exitcode=10)
491489

492490
def test_main_thread(self):
493491
main = threading.main_thread()
@@ -507,6 +505,7 @@ def f():
507505
def test_main_thread_after_fork(self):
508506
code = """if 1:
509507
import os, threading
508+
from test import support
510509
511510
pid = os.fork()
512511
if pid == 0:
@@ -515,7 +514,7 @@ def test_main_thread_after_fork(self):
515514
print(main.ident == threading.current_thread().ident)
516515
print(main.ident == threading.get_ident())
517516
else:
518-
os.waitpid(pid, 0)
517+
support.wait_process(pid, exitcode=0)
519518
"""
520519
_, out, err = assert_python_ok("-c", code)
521520
data = out.decode().replace('\r', '')
@@ -528,6 +527,7 @@ def test_main_thread_after_fork(self):
528527
def test_main_thread_after_fork_from_nonmain_thread(self):
529528
code = """if 1:
530529
import os, threading, sys
530+
from test import support
531531
532532
def f():
533533
pid = os.fork()
@@ -540,7 +540,7 @@ def f():
540540
# we have to flush before exit.
541541
sys.stdout.flush()
542542
else:
543-
os.waitpid(pid, 0)
543+
support.wait_process(pid, exitcode=0)
544544
545545
th = threading.Thread(target=f)
546546
th.start()
@@ -813,11 +813,15 @@ def test_1_join_on_shutdown(self):
813813
def test_2_join_in_forked_process(self):
814814
# Like the test above, but from a forked interpreter
815815
script = """if 1:
816+
from test import support
817+
816818
childpid = os.fork()
817819
if childpid != 0:
818-
os.waitpid(childpid, 0)
820+
# parent process
821+
support.wait_process(childpid, exitcode=0)
819822
sys.exit(0)
820823
824+
# child process
821825
t = threading.Thread(target=joiningfunc,
822826
args=(threading.current_thread(),))
823827
t.start()
@@ -832,13 +836,17 @@ def test_3_join_in_forked_from_thread(self):
832836
# In the forked process, the main Thread object must be marked as stopped.
833837

834838
script = """if 1:
839+
from test import support
840+
835841
main_thread = threading.current_thread()
836842
def worker():
837843
childpid = os.fork()
838844
if childpid != 0:
839-
os.waitpid(childpid, 0)
845+
# parent process
846+
support.wait_process(childpid, exitcode=0)
840847
sys.exit(0)
841848
849+
# child process
842850
t = threading.Thread(target=joiningfunc,
843851
args=(main_thread,))
844852
print('end of main')
@@ -901,9 +909,9 @@ def do_fork_and_wait():
901909
# just fork a child process and wait it
902910
pid = os.fork()
903911
if pid > 0:
904-
os.waitpid(pid, 0)
912+
support.wait_process(pid, exitcode=50)
905913
else:
906-
os._exit(0)
914+
os._exit(50)
907915

908916
# start a bunch of threads that will fork() child processes
909917
threads = []
@@ -930,12 +938,11 @@ def test_clear_threads_states_after_fork(self):
930938
if pid == 0:
931939
# check that threads states have been cleared
932940
if len(sys._current_frames()) == 1:
933-
os._exit(0)
941+
os._exit(51)
934942
else:
935-
os._exit(1)
943+
os._exit(52)
936944
else:
937-
_, status = os.waitpid(pid, 0)
938-
self.assertEqual(0, status)
945+
support.wait_process(pid, exitcode=51)
939946

940947
for t in threads:
941948
t.join()

0 commit comments

Comments
 (0)