summaryrefslogtreecommitdiff
path: root/packages/Python/lldbsuite/test/test_runner
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-01-02 19:26:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-01-02 19:26:05 +0000
commit14f1b3e8826ce43b978db93a62d1166055db5394 (patch)
tree0a00ad8d3498783fe0193f3b656bca17c4c8697d /packages/Python/lldbsuite/test/test_runner
parent4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff)
Notes
Diffstat (limited to 'packages/Python/lldbsuite/test/test_runner')
-rw-r--r--packages/Python/lldbsuite/test/test_runner/process_control.py62
-rwxr-xr-xpackages/Python/lldbsuite/test/test_runner/test/test_process_control.py13
2 files changed, 57 insertions, 18 deletions
diff --git a/packages/Python/lldbsuite/test/test_runner/process_control.py b/packages/Python/lldbsuite/test/test_runner/process_control.py
index a7e639e4b8b65..720f5112a4cd8 100644
--- a/packages/Python/lldbsuite/test/test_runner/process_control.py
+++ b/packages/Python/lldbsuite/test/test_runner/process_control.py
@@ -23,6 +23,7 @@ import threading
class CommunicatorThread(threading.Thread):
"""Provides a thread class that communicates with a subprocess."""
+
def __init__(self, process, event, output_file):
super(CommunicatorThread, self).__init__()
# Don't let this thread prevent shutdown.
@@ -100,6 +101,7 @@ class ProcessHelper(object):
@see ProcessHelper.process_helper()
"""
+
def __init__(self):
super(ProcessHelper, self).__init__()
@@ -281,6 +283,7 @@ class UnixProcessHelper(ProcessHelper):
This implementation supports anything that looks Posix-y
(e.g. Darwin, Linux, *BSD, etc.)
"""
+
def __init__(self):
super(UnixProcessHelper, self).__init__()
@@ -302,7 +305,7 @@ class UnixProcessHelper(ProcessHelper):
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
- universal_newlines=True, # Elicits automatic byte -> string decoding in Py3
+ universal_newlines=True, # Elicits automatic byte -> string decoding in Py3
close_fds=True,
preexec_fn=preexec_func)
@@ -357,18 +360,28 @@ class UnixProcessHelper(ProcessHelper):
# Choose kill mechanism based on whether we're targeting
# a process group or just a process.
- if popen_process.using_process_groups:
- # if log_file:
- # log_file.write(
- # "sending signum {} to process group {} now\n".format(
- # signum, popen_process.pid))
- os.killpg(popen_process.pid, signum)
- else:
- # if log_file:
- # log_file.write(
- # "sending signum {} to process {} now\n".format(
- # signum, popen_process.pid))
- os.kill(popen_process.pid, signum)
+ try:
+ if popen_process.using_process_groups:
+ # if log_file:
+ # log_file.write(
+ # "sending signum {} to process group {} now\n".format(
+ # signum, popen_process.pid))
+ os.killpg(popen_process.pid, signum)
+ else:
+ # if log_file:
+ # log_file.write(
+ # "sending signum {} to process {} now\n".format(
+ # signum, popen_process.pid))
+ os.kill(popen_process.pid, signum)
+ except OSError as error:
+ import errno
+ if error.errno == errno.ESRCH:
+ # This is okay - failed to find the process. It may be that
+ # that the timeout pre-kill hook eliminated the process. We'll
+ # ignore.
+ pass
+ else:
+ raise
def soft_terminate(self, popen_process, log_file=None, want_core=True):
# Choose signal based on desire for core file.
@@ -412,8 +425,10 @@ class UnixProcessHelper(ProcessHelper):
signal_name = signal_names_by_number.get(signo, "")
return (signo, signal_name)
+
class WindowsProcessHelper(ProcessHelper):
"""Provides a Windows implementation of the ProcessHelper class."""
+
def __init__(self):
super(WindowsProcessHelper, self).__init__()
@@ -429,7 +444,7 @@ class WindowsProcessHelper(ProcessHelper):
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
- universal_newlines=True, # Elicits automatic byte -> string decoding in Py3
+ universal_newlines=True, # Elicits automatic byte -> string decoding in Py3
creationflags=creation_flags)
def was_hard_terminate(self, returncode):
@@ -447,6 +462,7 @@ class ProcessDriver(object):
way. The on_process_exited method is informed if the exit was natural
or if it was due to a timeout.
"""
+
def __init__(self, soft_terminate_timeout=10.0):
super(ProcessDriver, self).__init__()
self.process_helper = ProcessHelper.process_helper()
@@ -477,6 +493,19 @@ class ProcessDriver(object):
def on_process_exited(self, command, output, was_timeout, exit_status):
pass
+ def on_timeout_pre_kill(self):
+ """Called after the timeout interval elapses but before killing it.
+
+ This method is added to enable derived classes the ability to do
+ something to the process prior to it being killed. For example,
+ this would be a good spot to run a program that samples the process
+ to see what it was doing (or not doing).
+
+ Do not attempt to reap the process (i.e. use wait()) in this method.
+ That will interfere with the kill mechanism and return code processing.
+ """
+ pass
+
def write(self, content):
# pylint: disable=no-self-use
# Intended - we want derived classes to be able to override
@@ -634,6 +663,11 @@ class ProcessDriver(object):
# Reap the child process here.
self.returncode = self.process.wait()
else:
+
+ # Allow derived classes to do some work after we detected
+ # a timeout but before we touch the timed-out process.
+ self.on_timeout_pre_kill()
+
# Prepare to stop the process
process_terminated = completed_normally
terminate_attempt_count = 0
diff --git a/packages/Python/lldbsuite/test/test_runner/test/test_process_control.py b/packages/Python/lldbsuite/test/test_runner/test/test_process_control.py
index 817c83c4fb55f..88ad961be2b9c 100755
--- a/packages/Python/lldbsuite/test/test_runner/test/test_process_control.py
+++ b/packages/Python/lldbsuite/test/test_runner/test/test_process_control.py
@@ -27,6 +27,7 @@ from test_runner import process_control
class TestInferiorDriver(process_control.ProcessDriver):
+
def __init__(self, soft_terminate_timeout=None):
super(TestInferiorDriver, self).__init__(
soft_terminate_timeout=soft_terminate_timeout)
@@ -58,6 +59,7 @@ class TestInferiorDriver(process_control.ProcessDriver):
class ProcessControlTests(unittest.TestCase):
+
@classmethod
def _suppress_soft_terminate(cls, command):
# Do the right thing for your platform here.
@@ -79,7 +81,8 @@ class ProcessControlTests(unittest.TestCase):
# Base command.
script_name = "{}/inferior.py".format(os.path.dirname(__file__))
if not os.path.exists(script_name):
- raise Exception("test inferior python script not found: {}".format(script_name))
+ raise Exception(
+ "test inferior python script not found: {}".format(script_name))
command = ([sys.executable, script_name])
if ignore_soft_terminate:
@@ -97,6 +100,7 @@ class ProcessControlTests(unittest.TestCase):
class ProcessControlNoTimeoutTests(ProcessControlTests):
"""Tests the process_control module."""
+
def test_run_completes(self):
"""Test that running completes and gets expected stdout/stderr."""
driver = TestInferiorDriver()
@@ -115,6 +119,7 @@ class ProcessControlNoTimeoutTests(ProcessControlTests):
class ProcessControlTimeoutTests(ProcessControlTests):
+
def test_run_completes(self):
"""Test that running completes and gets expected return code."""
driver = TestInferiorDriver()
@@ -124,7 +129,7 @@ class ProcessControlTimeoutTests(ProcessControlTests):
"{}s".format(timeout_seconds),
False)
self.assertTrue(
- driver.completed_event.wait(2*timeout_seconds),
+ driver.completed_event.wait(2 * timeout_seconds),
"process failed to complete")
self.assertEqual(driver.returncode, 0)
@@ -141,13 +146,13 @@ class ProcessControlTimeoutTests(ProcessControlTests):
# Sleep twice as long as the timeout interval. This
# should force a timeout.
self.inferior_command(
- options="--sleep {}".format(timeout_seconds*2)),
+ options="--sleep {}".format(timeout_seconds * 2)),
"{}s".format(timeout_seconds),
with_core)
# We should complete, albeit with a timeout.
self.assertTrue(
- driver.completed_event.wait(2*timeout_seconds),
+ driver.completed_event.wait(2 * timeout_seconds),
"process failed to complete")
# Ensure we received a timeout.