mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00:00
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.
This commit is contained in:
parent
27c6231f58
commit
a9f9687a7c
2 changed files with 39 additions and 31 deletions
|
@ -225,30 +225,31 @@ class TestForkInThread(unittest.TestCase):
|
||||||
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
|
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork')
|
||||||
@support.reap_threads
|
@support.reap_threads
|
||||||
def test_forkinthread(self):
|
def test_forkinthread(self):
|
||||||
status = "not set"
|
pid = None
|
||||||
|
|
||||||
def thread1():
|
def fork_thread(read_fd, write_fd):
|
||||||
nonlocal status
|
nonlocal pid
|
||||||
|
|
||||||
# fork in a thread
|
# fork in a thread
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid == 0:
|
if pid:
|
||||||
# child
|
# parent process
|
||||||
try:
|
return
|
||||||
os.close(self.read_fd)
|
|
||||||
os.write(self.write_fd, b"OK")
|
# child process
|
||||||
finally:
|
try:
|
||||||
os._exit(0)
|
os.close(read_fd)
|
||||||
else:
|
os.write(write_fd, b"OK")
|
||||||
# parent
|
finally:
|
||||||
os.close(self.write_fd)
|
os._exit(0)
|
||||||
pid, status = os.waitpid(pid, 0)
|
|
||||||
|
|
||||||
with support.wait_threads_exit():
|
with support.wait_threads_exit():
|
||||||
thread.start_new_thread(thread1, ())
|
thread.start_new_thread(fork_thread, (self.read_fd, self.write_fd))
|
||||||
self.assertEqual(os.read(self.read_fd, 2), b"OK",
|
self.assertEqual(os.read(self.read_fd, 2), b"OK")
|
||||||
"Unable to fork() in thread")
|
os.close(self.write_fd)
|
||||||
self.assertEqual(status, 0)
|
|
||||||
|
self.assertIsNotNone(pid)
|
||||||
|
support.wait_process(pid, exitcode=0)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -485,9 +485,7 @@ class ThreadTests(BaseTestCase):
|
||||||
else:
|
else:
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
pid, status = os.waitpid(pid, 0)
|
support.wait_process(pid, exitcode=10)
|
||||||
self.assertTrue(os.WIFEXITED(status))
|
|
||||||
self.assertEqual(10, os.WEXITSTATUS(status))
|
|
||||||
|
|
||||||
def test_main_thread(self):
|
def test_main_thread(self):
|
||||||
main = threading.main_thread()
|
main = threading.main_thread()
|
||||||
|
@ -507,6 +505,7 @@ class ThreadTests(BaseTestCase):
|
||||||
def test_main_thread_after_fork(self):
|
def test_main_thread_after_fork(self):
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import os, threading
|
import os, threading
|
||||||
|
from test import support
|
||||||
|
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
|
@ -515,7 +514,7 @@ class ThreadTests(BaseTestCase):
|
||||||
print(main.ident == threading.current_thread().ident)
|
print(main.ident == threading.current_thread().ident)
|
||||||
print(main.ident == threading.get_ident())
|
print(main.ident == threading.get_ident())
|
||||||
else:
|
else:
|
||||||
os.waitpid(pid, 0)
|
support.wait_process(pid, exitcode=0)
|
||||||
"""
|
"""
|
||||||
_, out, err = assert_python_ok("-c", code)
|
_, out, err = assert_python_ok("-c", code)
|
||||||
data = out.decode().replace('\r', '')
|
data = out.decode().replace('\r', '')
|
||||||
|
@ -528,6 +527,7 @@ class ThreadTests(BaseTestCase):
|
||||||
def test_main_thread_after_fork_from_nonmain_thread(self):
|
def test_main_thread_after_fork_from_nonmain_thread(self):
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
import os, threading, sys
|
import os, threading, sys
|
||||||
|
from test import support
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
|
@ -540,7 +540,7 @@ class ThreadTests(BaseTestCase):
|
||||||
# we have to flush before exit.
|
# we have to flush before exit.
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
else:
|
else:
|
||||||
os.waitpid(pid, 0)
|
support.wait_process(pid, exitcode=0)
|
||||||
|
|
||||||
th = threading.Thread(target=f)
|
th = threading.Thread(target=f)
|
||||||
th.start()
|
th.start()
|
||||||
|
@ -813,11 +813,15 @@ class ThreadJoinOnShutdown(BaseTestCase):
|
||||||
def test_2_join_in_forked_process(self):
|
def test_2_join_in_forked_process(self):
|
||||||
# Like the test above, but from a forked interpreter
|
# Like the test above, but from a forked interpreter
|
||||||
script = """if 1:
|
script = """if 1:
|
||||||
|
from test import support
|
||||||
|
|
||||||
childpid = os.fork()
|
childpid = os.fork()
|
||||||
if childpid != 0:
|
if childpid != 0:
|
||||||
os.waitpid(childpid, 0)
|
# parent process
|
||||||
|
support.wait_process(childpid, exitcode=0)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
# child process
|
||||||
t = threading.Thread(target=joiningfunc,
|
t = threading.Thread(target=joiningfunc,
|
||||||
args=(threading.current_thread(),))
|
args=(threading.current_thread(),))
|
||||||
t.start()
|
t.start()
|
||||||
|
@ -832,13 +836,17 @@ class ThreadJoinOnShutdown(BaseTestCase):
|
||||||
# In the forked process, the main Thread object must be marked as stopped.
|
# In the forked process, the main Thread object must be marked as stopped.
|
||||||
|
|
||||||
script = """if 1:
|
script = """if 1:
|
||||||
|
from test import support
|
||||||
|
|
||||||
main_thread = threading.current_thread()
|
main_thread = threading.current_thread()
|
||||||
def worker():
|
def worker():
|
||||||
childpid = os.fork()
|
childpid = os.fork()
|
||||||
if childpid != 0:
|
if childpid != 0:
|
||||||
os.waitpid(childpid, 0)
|
# parent process
|
||||||
|
support.wait_process(childpid, exitcode=0)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
# child process
|
||||||
t = threading.Thread(target=joiningfunc,
|
t = threading.Thread(target=joiningfunc,
|
||||||
args=(main_thread,))
|
args=(main_thread,))
|
||||||
print('end of main')
|
print('end of main')
|
||||||
|
@ -901,9 +909,9 @@ class ThreadJoinOnShutdown(BaseTestCase):
|
||||||
# just fork a child process and wait it
|
# just fork a child process and wait it
|
||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid > 0:
|
if pid > 0:
|
||||||
os.waitpid(pid, 0)
|
support.wait_process(pid, exitcode=50)
|
||||||
else:
|
else:
|
||||||
os._exit(0)
|
os._exit(50)
|
||||||
|
|
||||||
# start a bunch of threads that will fork() child processes
|
# start a bunch of threads that will fork() child processes
|
||||||
threads = []
|
threads = []
|
||||||
|
@ -930,12 +938,11 @@ class ThreadJoinOnShutdown(BaseTestCase):
|
||||||
if pid == 0:
|
if pid == 0:
|
||||||
# check that threads states have been cleared
|
# check that threads states have been cleared
|
||||||
if len(sys._current_frames()) == 1:
|
if len(sys._current_frames()) == 1:
|
||||||
os._exit(0)
|
os._exit(51)
|
||||||
else:
|
else:
|
||||||
os._exit(1)
|
os._exit(52)
|
||||||
else:
|
else:
|
||||||
_, status = os.waitpid(pid, 0)
|
support.wait_process(pid, exitcode=51)
|
||||||
self.assertEqual(0, status)
|
|
||||||
|
|
||||||
for t in threads:
|
for t in threads:
|
||||||
t.join()
|
t.join()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue