1
0
mirror of https://github.com/ARM-software/devlib.git synced 2025-02-12 07:58:07 +00:00

utis/misc: make check_output thread-safe

subprocess.Popen (used internally by check_output) is not thread-safe
and may cause a thread to lock up if called simultaneously from multiple
threads. See

	https://bugs.python.org/issue12739

This is fixed in Python 3.2, but since we're currently still on 2.7,
work around the issue by protecting the call with a lock.
This commit is contained in:
sergei Trofimov 2018-04-20 10:06:29 +01:00 committed by Marc Bonnici
parent b88b400d8d
commit 87b235638a

View File

@ -30,6 +30,7 @@ import pkgutil
import logging import logging
import random import random
import ctypes import ctypes
import threading
from operator import itemgetter from operator import itemgetter
from itertools import groupby from itertools import groupby
from functools import partial from functools import partial
@ -135,6 +136,9 @@ def preexec_function():
check_output_logger = logging.getLogger('check_output') check_output_logger = logging.getLogger('check_output')
# Popen is not thread safe. If two threads attempt to call it at the same time,
# one may lock up. See https://bugs.python.org/issue12739.
check_output_lock = threading.Lock()
def check_output(command, timeout=None, ignore=None, inputtext=None, **kwargs): def check_output(command, timeout=None, ignore=None, inputtext=None, **kwargs):
@ -158,9 +162,13 @@ def check_output(command, timeout=None, ignore=None, inputtext=None, **kwargs):
except OSError: except OSError:
pass # process may have already terminated. pass # process may have already terminated.
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, with check_output_lock:
stdin=subprocess.PIPE, process = subprocess.Popen(command,
preexec_fn=preexec_function, **kwargs) stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
preexec_fn=preexec_function,
**kwargs)
if timeout: if timeout:
timer = threading.Timer(timeout, callback, [process.pid, ]) timer = threading.Timer(timeout, callback, [process.pid, ])