summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2009-04-09 06:16:03 +0000
committerZac Medico <zmedico@gentoo.org>2009-04-09 06:16:03 +0000
commitd93059ac7e65fb71c6d18254c175731176781920 (patch)
treeb4fe29c6adb842ed70e7111310f1a9fb4dfe2a7e
parent43a864ffa96ebaecb98971e74cfeb35a42b9b34d (diff)
downloadportage-d93059ac7e65fb71c6d18254c175731176781920.tar.gz
portage-d93059ac7e65fb71c6d18254c175731176781920.tar.bz2
portage-d93059ac7e65fb71c6d18254c175731176781920.zip
Bug #264435 - Handle EAGAIN errors when writing to stdout, due to poorly
behaved subprocesses that set O_NONBLOCK mode on inherited file descriptors. TODO: When possible, avoid having child processes inherit stdio file descriptors from portage (maybe it can't be avoided with PROPERTIES=interactive). svn path=/main/trunk/; revision=13306
-rw-r--r--pym/_emerge/__init__.py37
1 files changed, 35 insertions, 2 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index 6b526564a..fc7b3e6ad 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -2426,8 +2426,41 @@ class SpawnProcess(SubProcess):
if buf:
if not self.background:
- buf.tofile(files.stdout)
- files.stdout.flush()
+ write_successful = False
+ failures = 0
+ while True:
+ try:
+ if not write_successful:
+ buf.tofile(files.stdout)
+ write_successful = True
+ files.stdout.flush()
+ break
+ except IOError, e:
+ if e.errno != errno.EAGAIN:
+ raise
+ del e
+ failures += 1
+ if failures > 50:
+ # Avoid a potentially infinite loop. In
+ # most cases, the failure count is zero
+ # and it's unlikely to exceed 1.
+ raise
+
+ # This means that a subprocess has put an inherited
+ # stdio file descriptor (typically stdin) into
+ # O_NONBLOCK mode. This is not acceptable (see bug
+ # #264435), so revert it. We need to use a loop
+ # here since there's a race condition due to
+ # parallel processes being able to change the
+ # flags on the inherited file descriptor.
+ # TODO: When possible, avoid having child processes
+ # inherit stdio file descriptors from portage
+ # (maybe it can't be avoided with
+ # PROPERTIES=interactive).
+ fcntl.fcntl(files.stdout.fileno(), fcntl.F_SETFL,
+ fcntl.fcntl(files.stdout.fileno(),
+ fcntl.F_GETFL) ^ os.O_NONBLOCK)
+
buf.tofile(files.log)
files.log.flush()
else: