summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorGuido van Rossum <guido@dropbox.com>2013-10-22 03:37:14 (GMT)
committerGuido van Rossum <guido@dropbox.com>2013-10-22 03:37:14 (GMT)
commit934f6ea7fb07e7a2cefefcc4e200e84aa7d5a5e0 (patch)
treeed85da52cc67d0d435b23fd2a813d139ec8008d8 /Lib/asyncio
parent8a0fe85fbedf003ab113fdeed1c3d8f21e49a324 (diff)
downloadcpython-934f6ea7fb07e7a2cefefcc4e200e84aa7d5a5e0.zip
cpython-934f6ea7fb07e7a2cefefcc4e200e84aa7d5a5e0.tar.gz
cpython-934f6ea7fb07e7a2cefefcc4e200e84aa7d5a5e0.tar.bz2
Switch subprocess stdin to a socketpair, attempting to fix issue #19293 (AIX hang).
Diffstat (limited to 'Lib/asyncio')
-rw-r--r--Lib/asyncio/unix_events.py29
1 files changed, 25 insertions, 4 deletions
diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py
index 8c0e09a..3807680 100644
--- a/Lib/asyncio/unix_events.py
+++ b/Lib/asyncio/unix_events.py
@@ -213,6 +213,9 @@ class _UnixReadPipeTransport(transports.ReadTransport):
self._loop = loop
self._pipe = pipe
self._fileno = pipe.fileno()
+ mode = os.fstat(self._fileno).st_mode
+ if not (stat.S_ISFIFO(mode) or stat.S_ISSOCK(mode)):
+ raise ValueError("Pipe transport is for pipes/sockets only.")
_set_nonblocking(self._fileno)
self._protocol = protocol
self._closing = False
@@ -275,21 +278,29 @@ class _UnixWritePipeTransport(transports.WriteTransport):
self._loop = loop
self._pipe = pipe
self._fileno = pipe.fileno()
- if not stat.S_ISFIFO(os.fstat(self._fileno).st_mode):
- raise ValueError("Pipe transport is for pipes only.")
+ mode = os.fstat(self._fileno).st_mode
+ is_socket = stat.S_ISSOCK(mode)
+ is_pipe = stat.S_ISFIFO(mode)
+ if not (is_socket or is_pipe):
+ raise ValueError("Pipe transport is for pipes/sockets only.")
_set_nonblocking(self._fileno)
self._protocol = protocol
self._buffer = []
self._conn_lost = 0
self._closing = False # Set when close() or write_eof() called.
- self._loop.add_reader(self._fileno, self._read_ready)
+
+ # On AIX, the reader trick only works for sockets.
+ # On other platforms it works for pipes and sockets.
+ # (Exception: OS X 10.4? Issue #19294.)
+ if is_socket or not sys.platform.startswith("aix"):
+ self._loop.add_reader(self._fileno, self._read_ready)
self._loop.call_soon(self._protocol.connection_made, self)
if waiter is not None:
self._loop.call_soon(waiter.set_result, None)
def _read_ready(self):
- # pipe was closed by peer
+ # Pipe was closed by peer.
self._close()
def write(self, data):
@@ -435,8 +446,15 @@ class _UnixSubprocessTransport(transports.SubprocessTransport):
self._loop = loop
self._pipes = {}
+ stdin_w = None
if stdin == subprocess.PIPE:
self._pipes[STDIN] = None
+ # Use a socket pair for stdin, since not all platforms
+ # support selecting read events on the write end of a
+ # socket (which we use in order to detect closing of the
+ # other end). Notably this is needed on AIX, and works
+ # just fine on other platforms.
+ stdin, stdin_w = self._loop._socketpair()
if stdout == subprocess.PIPE:
self._pipes[STDOUT] = None
if stderr == subprocess.PIPE:
@@ -448,6 +466,9 @@ class _UnixSubprocessTransport(transports.SubprocessTransport):
self._proc = subprocess.Popen(
args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr,
universal_newlines=False, bufsize=bufsize, **kwargs)
+ if stdin_w is not None:
+ stdin.close()
+ self._proc.stdin = open(stdin_w.detach(), 'rb', buffering=bufsize)
self._extra['subprocess'] = self._proc
def close(self):