Issue #25122: Fix test_eintr, kill child process on error

Some test_eintr hangs on waiting for the child process completion if an error
occurred on the parent. Kill the child process on error (in the parent)
to avoid the hang.
This commit is contained in:
Victor Stinner 2015-09-15 22:38:09 +02:00
parent d7bf45f5f7
commit 44879a0b18
1 changed files with 24 additions and 8 deletions

View File

@ -8,6 +8,7 @@ Signals are generated in-process using setitimer(ITIMER_REAL), which allows
sub-second periodicity (contrarily to signal()). sub-second periodicity (contrarily to signal()).
""" """
import contextlib
import faulthandler import faulthandler
import io import io
import os import os
@ -21,6 +22,16 @@ import unittest
from test import support from test import support
@contextlib.contextmanager
def kill_on_error(proc):
"""Context manager killing the subprocess if a Python exception is raised."""
with proc:
try:
yield proc
except:
proc.kill()
raise
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
class EINTRBaseTest(unittest.TestCase): class EINTRBaseTest(unittest.TestCase):
@ -38,7 +49,7 @@ class EINTRBaseTest(unittest.TestCase):
def setUpClass(cls): def setUpClass(cls):
cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None) cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None)
if hasattr(faulthandler, 'dump_traceback_later'): if hasattr(faulthandler, 'dump_traceback_later'):
# Most tests take less than 30 seconds, so 15 minutes should be # Most tests take less than 30 seconds, so 5 minutes should be
# enough. dump_traceback_later() is implemented with a thread, but # enough. dump_traceback_later() is implemented with a thread, but
# pthread_sigmask() is used to mask all signaled on this thread. # pthread_sigmask() is used to mask all signaled on this thread.
faulthandler.dump_traceback_later(5 * 60, exit=True) faulthandler.dump_traceback_later(5 * 60, exit=True)
@ -120,7 +131,8 @@ class OSEINTRTest(EINTRBaseTest):
' os.write(wr, data)', ' os.write(wr, data)',
)) ))
with self.subprocess(code, str(wr), pass_fds=[wr]) as proc: proc = self.subprocess(code, str(wr), pass_fds=[wr])
with kill_on_error(proc):
os.close(wr) os.close(wr)
for data in datas: for data in datas:
self.assertEqual(data, os.read(rd, len(data))) self.assertEqual(data, os.read(rd, len(data)))
@ -156,7 +168,8 @@ class OSEINTRTest(EINTRBaseTest):
' % (len(value), data_len))', ' % (len(value), data_len))',
)) ))
with self.subprocess(code, str(rd), pass_fds=[rd]) as proc: proc = self.subprocess(code, str(rd), pass_fds=[rd])
with kill_on_error(proc):
os.close(rd) os.close(rd)
written = 0 written = 0
while written < len(data): while written < len(data):
@ -198,7 +211,7 @@ class SocketEINTRTest(EINTRBaseTest):
fd = wr.fileno() fd = wr.fileno()
proc = self.subprocess(code, str(fd), pass_fds=[fd]) proc = self.subprocess(code, str(fd), pass_fds=[fd])
with proc: with kill_on_error(proc):
wr.close() wr.close()
for data in datas: for data in datas:
self.assertEqual(data, recv_func(rd, len(data))) self.assertEqual(data, recv_func(rd, len(data)))
@ -248,7 +261,7 @@ class SocketEINTRTest(EINTRBaseTest):
fd = rd.fileno() fd = rd.fileno()
proc = self.subprocess(code, str(fd), pass_fds=[fd]) proc = self.subprocess(code, str(fd), pass_fds=[fd])
with proc: with kill_on_error(proc):
rd.close() rd.close()
written = 0 written = 0
while written < len(data): while written < len(data):
@ -288,7 +301,8 @@ class SocketEINTRTest(EINTRBaseTest):
' time.sleep(sleep_time)', ' time.sleep(sleep_time)',
)) ))
with self.subprocess(code) as proc: proc = self.subprocess(code)
with kill_on_error(proc):
client_sock, _ = sock.accept() client_sock, _ = sock.accept()
client_sock.close() client_sock.close()
self.assertEqual(proc.wait(), 0) self.assertEqual(proc.wait(), 0)
@ -315,7 +329,8 @@ class SocketEINTRTest(EINTRBaseTest):
do_open_close_reader, do_open_close_reader,
)) ))
with self.subprocess(code) as proc: proc = self.subprocess(code)
with kill_on_error(proc):
do_open_close_writer(filename) do_open_close_writer(filename)
self.assertEqual(proc.wait(), 0) self.assertEqual(proc.wait(), 0)
@ -372,7 +387,8 @@ class SignalEINTRTest(EINTRBaseTest):
)) ))
t0 = time.monotonic() t0 = time.monotonic()
with self.subprocess(code) as proc: proc = self.subprocess(code)
with kill_on_error(proc):
# parent # parent
signal.sigwaitinfo([signum]) signal.sigwaitinfo([signum])
dt = time.monotonic() - t0 dt = time.monotonic() - t0