From: Victor Stinner Date: Tue, 15 Sep 2015 20:38:09 +0000 (+0200) Subject: Issue #25122: Fix test_eintr, kill child process on error X-Git-Tag: v3.6.0a1~1543 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=44879a0b18048e2d722a866e3ec0485012bce732;p=python 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. --- diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py index b96f09b691..e1330a71b1 100644 --- a/Lib/test/eintrdata/eintr_tester.py +++ b/Lib/test/eintrdata/eintr_tester.py @@ -8,6 +8,7 @@ Signals are generated in-process using setitimer(ITIMER_REAL), which allows sub-second periodicity (contrarily to signal()). """ +import contextlib import faulthandler import io import os @@ -21,6 +22,16 @@ import unittest 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()") class EINTRBaseTest(unittest.TestCase): @@ -38,7 +49,7 @@ class EINTRBaseTest(unittest.TestCase): def setUpClass(cls): cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None) 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 # pthread_sigmask() is used to mask all signaled on this thread. faulthandler.dump_traceback_later(5 * 60, exit=True) @@ -120,7 +131,8 @@ class OSEINTRTest(EINTRBaseTest): ' 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) for data in datas: self.assertEqual(data, os.read(rd, len(data))) @@ -156,7 +168,8 @@ class OSEINTRTest(EINTRBaseTest): ' % (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) written = 0 while written < len(data): @@ -198,7 +211,7 @@ class SocketEINTRTest(EINTRBaseTest): fd = wr.fileno() proc = self.subprocess(code, str(fd), pass_fds=[fd]) - with proc: + with kill_on_error(proc): wr.close() for data in datas: self.assertEqual(data, recv_func(rd, len(data))) @@ -248,7 +261,7 @@ class SocketEINTRTest(EINTRBaseTest): fd = rd.fileno() proc = self.subprocess(code, str(fd), pass_fds=[fd]) - with proc: + with kill_on_error(proc): rd.close() written = 0 while written < len(data): @@ -288,7 +301,8 @@ class SocketEINTRTest(EINTRBaseTest): ' 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.close() self.assertEqual(proc.wait(), 0) @@ -315,7 +329,8 @@ class SocketEINTRTest(EINTRBaseTest): do_open_close_reader, )) - with self.subprocess(code) as proc: + proc = self.subprocess(code) + with kill_on_error(proc): do_open_close_writer(filename) self.assertEqual(proc.wait(), 0) @@ -372,7 +387,8 @@ class SignalEINTRTest(EINTRBaseTest): )) t0 = time.monotonic() - with self.subprocess(code) as proc: + proc = self.subprocess(code) + with kill_on_error(proc): # parent signal.sigwaitinfo([signum]) dt = time.monotonic() - t0