| Index: subprocess2.py
|
| diff --git a/subprocess2.py b/subprocess2.py
|
| index 21e34878516b20ca7b260420d9a526cd0eb40b4a..a00592f4774a83eaa8e697d38c8ab7a921903fa9 100644
|
| --- a/subprocess2.py
|
| +++ b/subprocess2.py
|
| @@ -181,6 +181,14 @@ class Popen(subprocess.Popen):
|
| Note: Popen() can throw OSError when cwd or args[0] doesn't exist. Translate
|
| exceptions generated by cygwin when it fails trying to emulate fork().
|
| """
|
| + # subprocess.Popen.__init__() is not threadsafe; there is a race between
|
| + # creating the exec-error pipe for the child and setting it to CLOEXEC during
|
| + # which another thread can fork and cause the pipe to be inherited by its
|
| + # descendents, which will cause the current Popen to hang until all those
|
| + # descendents exit. Protect this with a lock so that only one fork/exec can
|
| + # happen at a time.
|
| + popen_lock = threading.Lock()
|
| +
|
| def __init__(self, args, **kwargs):
|
| # Make sure we hack subprocess if necessary.
|
| hack_subprocess()
|
| @@ -234,7 +242,8 @@ class Popen(subprocess.Popen):
|
| self.returncode = None
|
|
|
| try:
|
| - super(Popen, self).__init__(args, **kwargs)
|
| + with self.popen_lock:
|
| + super(Popen, self).__init__(args, **kwargs)
|
| except OSError, e:
|
| if e.errno == errno.EAGAIN and sys.platform == 'cygwin':
|
| # Convert fork() emulation failure into a CygwinRebaseError().
|
|
|