[rhel7-branch 1/1] Really fix unexpected exits in execReadlines

dashea installerbot-noreply at redhat.com
Fri Jul 24 18:31:15 UTC 2015


From: David Shea <dshea at redhat.com>

Due to the asynchronous nature of signal delivery, it's possible to
check on the execReadlines child process at a point where output has
been closed but the process is still, technically, alive. This situation
appeared in particular when running the nosetests on a system with one
CPU. To make the behavior of reading a line from an exiting process
deterministic, wait for the process to finish when output is complete.
The consequence of this is that processes that runs forever will cause
execReadlines to block forever, and the answer is to not run such a
process with execReadlines.

This commit also combines the fix for the bad use of WIFSIGNALED in
2275dfc76f4417cbe1b620d19b6558ec007d3bdc and the change in
807aa60ccb3cc0bc74581b58f04d0777d7b35985 to make the exit behavior make
more sense. The tests were already looking for the exceptions raised by
the latter commit, and sometimes they found them.

(cherry picked from commit 807aa60ccb3cc0bc74581b58f04d0777d7b35985)

Related: rhbz#1188287
---
 pyanaconda/iutil.py | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
index 413bc30..c827431 100644
--- a/pyanaconda/iutil.py
+++ b/pyanaconda/iutil.py
@@ -346,6 +346,10 @@ def execReadlines(command, argv, stdin=None, root='/', env_prune=None):
     """ Execute an external command and return the line output of the command
         in real-time.
 
+        This method assumes that there is a reasonably low delay between the
+        end of output and the process exiting. If the child process closes
+        stdout and then keeps on truckin' there will be problems.
+
         :param command: The command to run
         :param argv: The argument list
         :param stdin: The file object to read stdin from.
@@ -383,11 +387,16 @@ def next(self):
             # Read the next line, blocking if a line is not yet available
             line = self._proc.stdout.readline()
             if line == '':
-                # Output finished, check for the process dying unexpectedly
-                # and stop the iteration
-                if self._proc.poll() is not None:
-                    if os.WIFSIGNALED(self._proc.returncode):
-                        raise OSError("process '%s' was killed" % self._argv)
+                # Output finished, wait for the process to end
+                self._proc.communicate()
+
+                # Check for successful exit
+                if self._proc.returncode < 0:
+                    raise OSError("process '%s' was killed by signal %s" %
+                            (self._argv, -self._proc.returncode))
+                elif self._proc.returncode > 0:
+                    raise OSError("process '%s' exited with status %s" %
+                            (self._argv, self._proc.returncode))
                 raise StopIteration
 
             return line.strip()


-- 
To view this commit on github, visit https://github.com/rhinstaller/anaconda/commit/812560b33ac18af49faf3023d8f18cadf7e0f848


More information about the anaconda-patches mailing list