Fix race on subprocess.Popen return values.

This fixes:
https://llvm.org/bugs/show_bug.cgi?id=25019

llvm-svn: 249182
This commit is contained in:
Todd Fiala 2015-10-02 20:51:11 +00:00
parent b85db178a0
commit ae5dee8031
2 changed files with 49 additions and 1 deletions

View File

@ -611,3 +611,48 @@ class ProcessDriver(object):
self.io_thread.output, self.io_thread.output,
not completed_normally, not completed_normally,
self.returncode) self.returncode)
def patched_init(self, *args, **kwargs):
self.original_init(*args, **kwargs)
# Initialize our condition variable that protects wait()/poll().
self.wait_condition = threading.Condition()
def patched_wait(self):
self.wait_condition.acquire()
try:
result = self.original_wait()
# The process finished. Signal the condition.
self.wait_condition.notify_all()
return result
finally:
self.wait_condition.release()
def patched_poll(self):
self.wait_condition.acquire()
try:
result = self.original_poll()
if self.returncode is not None:
# We did complete, and we have the return value.
# Signal the event to indicate we're done.
self.wait_condition.notify_all()
return result
finally:
self.wait_condition.release()
def patch_up_subprocess_popen():
subprocess.Popen.original_init = subprocess.Popen.__init__
subprocess.Popen.__init__ = patched_init
subprocess.Popen.original_wait = subprocess.Popen.wait
subprocess.Popen.wait = patched_wait
subprocess.Popen.original_poll = subprocess.Popen.poll
subprocess.Popen.poll = patched_poll
# Replace key subprocess.Popen() threading-unprotected methods with
# threading-protected versions.
patch_up_subprocess_popen()

View File

@ -202,6 +202,9 @@ class ProcessControlTimeoutTests(ProcessControlTests):
"""inferior exit detected when inferior children are live with shared """inferior exit detected when inferior children are live with shared
stdout/stderr handles. stdout/stderr handles.
""" """
# Requires review D13362 or equivalent to be implemented.
self.skipTest("http://reviews.llvm.org/D13362")
driver = TestInferiorDriver() driver = TestInferiorDriver()
# Create the inferior (I1), and instruct it to create a child (C1) # Create the inferior (I1), and instruct it to create a child (C1)
@ -220,7 +223,7 @@ class ProcessControlTimeoutTests(ProcessControlTests):
"process failed to complete") "process failed to complete")
# Ensure we didn't receive a timeout. # Ensure we didn't receive a timeout.
self.assertTrue( self.assertFalse(
driver.was_timeout, "inferior should have completed normally") driver.was_timeout, "inferior should have completed normally")
self.assertEqual( self.assertEqual(