mirror of
https://github.com/ARM-software/devlib.git
synced 2025-01-31 02:00:45 +00:00
devlib.utils.misc: Use Popen.communicate(timeout=...) in check_output
Use the timeout parameter added in Python 3.3, which removes the need for the timer thread and avoids some weird issues in preexec_fn, as it's now documented to sometimes not work when threads are involved.
This commit is contained in:
parent
92e16ee873
commit
98e2e51d09
@ -136,9 +136,6 @@ def get_cpu_name(implementer, part, variant):
|
||||
|
||||
|
||||
def preexec_function():
|
||||
# Ignore the SIGINT signal by setting the handler to the standard
|
||||
# signal handler SIG_IGN.
|
||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||
# Change process group in case we have to kill the subprocess and all of
|
||||
# its children later.
|
||||
# TODO: this is Unix-specific; would be good to find an OS-agnostic way
|
||||
@ -167,13 +164,6 @@ def check_output(command, timeout=None, ignore=None, inputtext=None,
|
||||
if 'stdout' in kwargs:
|
||||
raise ValueError('stdout argument not allowed, it will be overridden.')
|
||||
|
||||
def callback(pid):
|
||||
try:
|
||||
check_output_logger.debug('{} timed out; sending SIGKILL'.format(pid))
|
||||
os.killpg(pid, signal.SIGKILL)
|
||||
except OSError:
|
||||
pass # process may have already terminated.
|
||||
|
||||
with check_output_lock:
|
||||
stderr = subprocess.STDOUT if combined_output else subprocess.PIPE
|
||||
process = subprocess.Popen(command,
|
||||
@ -183,26 +173,23 @@ def check_output(command, timeout=None, ignore=None, inputtext=None,
|
||||
preexec_fn=preexec_function,
|
||||
**kwargs)
|
||||
|
||||
if timeout:
|
||||
timer = threading.Timer(timeout, callback, [process.pid, ])
|
||||
timer.start()
|
||||
|
||||
try:
|
||||
output, error = process.communicate(inputtext)
|
||||
if sys.version_info[0] == 3:
|
||||
output, error = process.communicate(inputtext, timeout=timeout)
|
||||
except subprocess.TimeoutExpired as e:
|
||||
timeout_expired = e
|
||||
else:
|
||||
timeout_expired = None
|
||||
|
||||
# Currently errors=replace is needed as 0x8c throws an error
|
||||
output = output.decode(sys.stdout.encoding or 'utf-8', "replace")
|
||||
if error:
|
||||
error = error.decode(sys.stderr.encoding or 'utf-8', "replace")
|
||||
finally:
|
||||
if timeout:
|
||||
timer.cancel()
|
||||
|
||||
if timeout_expired:
|
||||
raise TimeoutError(command, output='\n'.join([output or '', error or '']))
|
||||
|
||||
retcode = process.poll()
|
||||
if retcode:
|
||||
if retcode == -9: # killed, assume due to timeout callback
|
||||
raise TimeoutError(command, output='\n'.join([output or '', error or '']))
|
||||
elif ignore != 'all' and retcode not in ignore:
|
||||
if retcode and ignore != 'all' and retcode not in ignore:
|
||||
raise subprocess.CalledProcessError(retcode, command, output='\n'.join([output or '', error or '']))
|
||||
return output, error
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user