1 |
Author: zmedico |
2 |
Date: 2009-04-09 06:16:03 +0000 (Thu, 09 Apr 2009) |
3 |
New Revision: 13306 |
4 |
|
5 |
Modified: |
6 |
main/trunk/pym/_emerge/__init__.py |
7 |
Log: |
8 |
Bug #264435 - Handle EAGAIN errors when writing to stdout, due to poorly |
9 |
behaved subprocesses that set O_NONBLOCK mode on inherited file descriptors. |
10 |
TODO: When possible, avoid having child processes inherit stdio file |
11 |
descriptors from portage (maybe it can't be avoided with |
12 |
PROPERTIES=interactive). |
13 |
|
14 |
|
15 |
Modified: main/trunk/pym/_emerge/__init__.py |
16 |
=================================================================== |
17 |
--- main/trunk/pym/_emerge/__init__.py 2009-04-08 20:48:08 UTC (rev 13305) |
18 |
+++ main/trunk/pym/_emerge/__init__.py 2009-04-09 06:16:03 UTC (rev 13306) |
19 |
@@ -2426,8 +2426,41 @@ |
20 |
|
21 |
if buf: |
22 |
if not self.background: |
23 |
- buf.tofile(files.stdout) |
24 |
- files.stdout.flush() |
25 |
+ write_successful = False |
26 |
+ failures = 0 |
27 |
+ while True: |
28 |
+ try: |
29 |
+ if not write_successful: |
30 |
+ buf.tofile(files.stdout) |
31 |
+ write_successful = True |
32 |
+ files.stdout.flush() |
33 |
+ break |
34 |
+ except IOError, e: |
35 |
+ if e.errno != errno.EAGAIN: |
36 |
+ raise |
37 |
+ del e |
38 |
+ failures += 1 |
39 |
+ if failures > 50: |
40 |
+ # Avoid a potentially infinite loop. In |
41 |
+ # most cases, the failure count is zero |
42 |
+ # and it's unlikely to exceed 1. |
43 |
+ raise |
44 |
+ |
45 |
+ # This means that a subprocess has put an inherited |
46 |
+ # stdio file descriptor (typically stdin) into |
47 |
+ # O_NONBLOCK mode. This is not acceptable (see bug |
48 |
+ # #264435), so revert it. We need to use a loop |
49 |
+ # here since there's a race condition due to |
50 |
+ # parallel processes being able to change the |
51 |
+ # flags on the inherited file descriptor. |
52 |
+ # TODO: When possible, avoid having child processes |
53 |
+ # inherit stdio file descriptors from portage |
54 |
+ # (maybe it can't be avoided with |
55 |
+ # PROPERTIES=interactive). |
56 |
+ fcntl.fcntl(files.stdout.fileno(), fcntl.F_SETFL, |
57 |
+ fcntl.fcntl(files.stdout.fileno(), |
58 |
+ fcntl.F_GETFL) ^ os.O_NONBLOCK) |
59 |
+ |
60 |
buf.tofile(files.log) |
61 |
files.log.flush() |
62 |
else: |