]> granicus.if.org Git - python/commitdiff
Issue #25122: Fix test_eintr, kill child process on error
authorVictor Stinner <victor.stinner@gmail.com>
Tue, 15 Sep 2015 20:38:09 +0000 (22:38 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 15 Sep 2015 20:38:09 +0000 (22:38 +0200)
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.

Lib/test/eintrdata/eintr_tester.py

index b96f09b691980eb194fe006b07fd41f37fe57cc2..e1330a71b1b82c8585085459c46db30f755b7b44 100644 (file)
@@ -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