Commit e3bd13bb authored by Colomban Wendling's avatar Colomban Wendling

Move workaround for threaded Popen Python bug to subprocess compat

Move workaround for Python bug http://bugs.python.org/issue18851 to
lib/subprocess_compat.py.
parent 90c56ed7
from lib.subprocess_compat import TimeoutExpired, Popen, PIPE
from threading import Lock
import re
# used for hack in Check.exec_with_timeout() because Popen is not
# atomic when failing to spawn command
# see http://bugs.python.org/issue18851
lock = Lock()
class Host(object):
def __init__(self, ipv4, ipv6):
self.ipv4 = ipv4
......@@ -65,13 +58,10 @@ class Check(object):
def exec_with_timeout(self, command, timeout=2, pattern=''):
self.errmsg = ''
try:
lock.acquire()
p = Popen(command, stdout=PIPE, stderr=PIPE)
except OSError as e:
self.errmsg = 'Check not available: ' + e.strerror
return False
finally:
lock.release()
try:
out, err = p.communicate(timeout=timeout)
except TimeoutExpired:
......
......@@ -4,7 +4,8 @@ from sys import hexversion as sys_hexversion
# Import or implement Popen() with timeout support
if sys_hexversion >= 0x03030000:
# on Python 3.3 Popen() supports timeout, we have nothing to do
from subprocess import TimeoutExpired, Popen, PIPE
from subprocess import TimeoutExpired, PIPE
from subprocess import Popen as _Popen_with_timeout
else:
# on Python < 3.3, implement timeout with a thread
from threading import Thread
......@@ -19,14 +20,14 @@ else:
return 'Command %s timed out after %g seconds' % (self.args,
self.timeout)
class Popen(subprocess.Popen):
class _Popen_with_timeout(subprocess.Popen):
def __init__(self, args, *pargs, **kwargs):
self.args = args
super().__init__(args=args, *pargs, **kwargs)
self._out = None
self._err = None
self._exc = None
self._thread = None
super().__init__(args=args, *pargs, **kwargs)
def _communicate_thread(self, input=None):
try:
......@@ -57,3 +58,24 @@ else:
if self._exc:
raise self._exc
return self._out, self._err
# Fix for bug http://bugs.python.org/issue18851
# FIXME: double check versions
# found in 3.2.0r1, fixed in 3.3.3
# found in 3.4.0, fixed in 3.4.0a1
if not ((sys_hexversion >= 0x030200C1 and sys_hexversion < 0x030303F0) or
(sys_hexversion >= 0x03040000 and sys_hexversion < 0x030400A1)):
class Popen(_Popen_with_timeout):
pass
else:
# as subprocess.Popen is not atomic when failing to spawn command,
# lock globally (see above)
from threading import Lock
_Popen_lock = Lock()
class Popen(_Popen_with_timeout):
def __init__(self, *args, **kwargs):
with _Popen_lock:
super().__init__(*args, **kwargs)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment