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