From 87b235638a6b87291f82d5f017629a2796050f4b Mon Sep 17 00:00:00 2001 From: sergei Trofimov Date: Fri, 20 Apr 2018 10:06:29 +0100 Subject: [PATCH] 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. --- devlib/utils/misc.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/devlib/utils/misc.py b/devlib/utils/misc.py index 235db6d..da19ba2 100644 --- a/devlib/utils/misc.py +++ b/devlib/utils/misc.py @@ -30,6 +30,7 @@ import pkgutil import logging import random import ctypes +import threading from operator import itemgetter from itertools import groupby from functools import partial @@ -135,6 +136,9 @@ def preexec_function(): 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): @@ -158,9 +162,13 @@ def check_output(command, timeout=None, ignore=None, inputtext=None, **kwargs): except OSError: pass # process may have already terminated. - process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - preexec_fn=preexec_function, **kwargs) + with check_output_lock: + process = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + preexec_fn=preexec_function, + **kwargs) if timeout: timer = threading.Timer(timeout, callback, [process.pid, ])