summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-09-15 20:38:09 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2015-09-15 20:38:09 (GMT)
commit44879a0b18048e2d722a866e3ec0485012bce732 (patch)
tree82cd75a96c6c12e046e7a791100b3dd0fee747d4
parentd7bf45f5f799b698ea84be564d3d82568b0446a7 (diff)
downloadcpython-44879a0b18048e2d722a866e3ec0485012bce732.zip
cpython-44879a0b18048e2d722a866e3ec0485012bce732.tar.gz
cpython-44879a0b18048e2d722a866e3ec0485012bce732.tar.bz2
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.
-rw-r--r--Lib/test/eintrdata/eintr_tester.py32
1 files changed, 24 insertions, 8 deletions
diff --git a/Lib/test/eintrdata/eintr_tester.py b/Lib/test/eintrdata/eintr_tester.py
index b96f09b..e1330a7 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