diff --git a/third_party/android_testrunner/run_command.py b/third_party/android_testrunner/run_command.py index d398daa..6b84156 100644 --- a/third_party/android_testrunner/run_command.py +++ b/third_party/android_testrunner/run_command.py @@ -19,6 +19,7 @@ import os import signal import subprocess +import tempfile import threading import time @@ -80,31 +81,36 @@ def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None): """ start_time = time.time() so = [] - pid = [] global _abort_on_error, error_occurred error_occurred = False + if return_output: + output_dest = tempfile.TemporaryFile(bufsize=0) + else: + # None means direct to stdout + output_dest = None + if stdin_input: + stdin_dest = subprocess.PIPE + else: + stdin_dest = None + pipe = subprocess.Popen( + cmd, + executable='/bin/bash', + stdin=stdin_dest, + stdout=output_dest, + stderr=subprocess.STDOUT, + shell=True, close_fds=True, + preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)) + def Run(): global error_occurred - if return_output: - output_dest = subprocess.PIPE - else: - # None means direct to stdout - output_dest = None - if stdin_input: - stdin_dest = subprocess.PIPE - else: - stdin_dest = None - pipe = subprocess.Popen( - cmd, - executable='/bin/bash', - stdin=stdin_dest, - stdout=output_dest, - stderr=subprocess.STDOUT, - shell=True) - pid.append(pipe.pid) try: - output = pipe.communicate(input=stdin_input)[0] + pipe.communicate(input=stdin_input) + output = None + if return_output: + output_dest.seek(0) + output = output_dest.read() + output_dest.close() if output is not None and len(output) > 0: so.append(output) except OSError, e: @@ -119,27 +125,17 @@ def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None): t = threading.Thread(target=Run) t.start() - - break_loop = False - while not break_loop: - if not t.isAlive(): - break_loop = True - - # Check the timeout - if (not break_loop and timeout_time is not None - and time.time() > start_time + timeout_time): - try: - os.kill(pid[0], signal.SIGKILL) - except OSError: - # process already dead. No action required. - pass - + t.join(timeout_time) + if t.isAlive(): + try: + pipe.kill() + except OSError: + # Can't kill a dead process. + pass + finally: logger.SilentLog("about to raise a timeout for: %s" % cmd) raise errors.WaitForResponseTimedOutError - if not break_loop: - time.sleep(0.1) - t.join() output = "".join(so) if _abort_on_error and error_occurred: raise errors.AbortError(msg=output)