lit: When executing shell scripts internally, don't allow piped stderr on any
authorDaniel Dunbar <daniel@zuster.org>
Tue, 22 Sep 2009 09:50:38 +0000 (09:50 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Tue, 22 Sep 2009 09:50:38 +0000 (09:50 +0000)
commands except the last one, instead redirect the stderr to a temporary
file. This sidesteps a potential deadlocking issue.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@82538 91177308-0d34-0410-b5e6-96231b3b80d8

utils/lit/TestRunner.py

index 2995196fe417b3d3894ffa9718530a2672cf5b51..7b549ac1c6156dcaf391794ceafd4c126061b2dc 100644 (file)
@@ -6,6 +6,7 @@ import Test
 import Util
 
 import platform
+import tempfile
 
 class InternalShellError(Exception):
     def __init__(self, command, message):
@@ -57,7 +58,11 @@ def executeShCmd(cmd, cfg, cwd, results):
     assert isinstance(cmd, ShUtil.Pipeline)
     procs = []
     input = subprocess.PIPE
-    for j in cmd.commands:
+    stderrTempFiles = []
+    # To avoid deadlock, we use a single stderr stream for piped
+    # output. This is null until we have seen some output using
+    # stderr.
+    for i,j in enumerate(cmd.commands):
         redirects = [(0,), (1,), (2,)]
         for r in j.redirects:
             if r[0] == ('>',2):
@@ -104,6 +109,14 @@ def executeShCmd(cmd, cfg, cwd, results):
         else:
             stderrIsStdout = False
 
+            # Don't allow stderr on a PIPE except for the last
+            # process, this could deadlock.
+            #
+            # FIXME: This is slow, but so is deadlock.
+            if stderr == subprocess.PIPE and j != cmd.commands[-1]:
+                stderr = tempfile.TemporaryFile(mode='w+b')
+                stderrTempFiles.append((i, stderr))
+
         # Resolve the executable path ourselves.
         args = list(j.args)
         args[0] = Util.which(args[0], cfg.environment['PATH'])
@@ -130,10 +143,10 @@ def executeShCmd(cmd, cfg, cwd, results):
         else:
             input = subprocess.PIPE
 
-    # FIXME: There is a potential for deadlock here, when we have a pipe and
-    # some process other than the last one ends up blocked on stderr.
+    # FIXME: There is probably still deadlock potential here. Yawn.
     procData = [None] * len(procs)
     procData[-1] = procs[-1].communicate()
+
     for i in range(len(procs) - 1):
         if procs[i].stdout is not None:
             out = procs[i].stdout.read()
@@ -144,6 +157,11 @@ def executeShCmd(cmd, cfg, cwd, results):
         else:
             err = ''
         procData[i] = (out,err)
+        
+    # Read stderr out of the temp files.
+    for i,f in stderrTempFiles:
+        f.seek(0, 0)
+        procData[i] = (procData[i][0], f.read())
 
     exitCode = None
     for i,(out,err) in enumerate(procData):