cpython: 2a0bda8d283d (original) (raw)
Mercurial > cpython
changeset 86557:2a0bda8d283d
Switch subprocess stdin to a socketpair, attempting to fix issue #19293 (AIX hang). [#19293]
Guido van Rossum guido@dropbox.com | |
---|---|
date | Mon, 21 Oct 2013 20:37:14 -0700 |
parents | df2b2b1f1289 |
children | b9019b942435 |
files | Lib/asyncio/unix_events.py Lib/test/test_asyncio/test_unix_events.py |
diffstat | 2 files changed, 32 insertions(+), 4 deletions(-)[+] [-] Lib/asyncio/unix_events.py 29 Lib/test/test_asyncio/test_unix_events.py 7 |
line wrap: on
line diff
--- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -213,6 +213,9 @@ class _UnixReadPipeTransport(transports. self._loop = loop self._pipe = pipe self._fileno = pipe.fileno()
mode = os.fstat(self._fileno).st_mode[](#l1.7)
if not (stat.S_ISFIFO(mode) or stat.S_ISSOCK(mode)):[](#l1.8)
raise ValueError("Pipe transport is for pipes/sockets only.")[](#l1.9) _set_nonblocking(self._fileno)[](#l1.10) self._protocol = protocol[](#l1.11) self._closing = False[](#l1.12)
@@ -275,21 +278,29 @@ class _UnixWritePipeTransport(transports self._loop = loop self._pipe = pipe self._fileno = pipe.fileno()
if not stat.S_ISFIFO(os.fstat(self._fileno).st_mode):[](#l1.17)
raise ValueError("Pipe transport is for pipes only.")[](#l1.18)
mode = os.fstat(self._fileno).st_mode[](#l1.19)
is_socket = stat.S_ISSOCK(mode)[](#l1.20)
is_pipe = stat.S_ISFIFO(mode)[](#l1.21)
if not (is_socket or is_pipe):[](#l1.22)
raise ValueError("Pipe transport is for pipes/sockets only.")[](#l1.23) _set_nonblocking(self._fileno)[](#l1.24) self._protocol = protocol[](#l1.25) self._buffer = [][](#l1.26) self._conn_lost = 0[](#l1.27) self._closing = False # Set when close() or write_eof() called.[](#l1.28)
self._loop.add_reader(self._fileno, self._read_ready)[](#l1.29)
# On AIX, the reader trick only works for sockets.[](#l1.31)
# On other platforms it works for pipes and sockets.[](#l1.32)
# (Exception: OS X 10.4? Issue #19294.)[](#l1.33)
if is_socket or not sys.platform.startswith("aix"):[](#l1.34)
self._loop.add_reader(self._fileno, self._read_ready)[](#l1.35)
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[](#l1.42)
# Pipe was closed by peer.[](#l1.43) self._close()[](#l1.44)
def write(self, data): @@ -435,8 +446,15 @@ class _UnixSubprocessTransport(transport self._loop = loop self._pipes = {}
stdin_w = None[](#l1.51) if stdin == subprocess.PIPE:[](#l1.52) self._pipes[STDIN] = None[](#l1.53)
# Use a socket pair for stdin, since not all platforms[](#l1.54)
# support selecting read events on the write end of a[](#l1.55)
# socket (which we use in order to detect closing of the[](#l1.56)
# other end). Notably this is needed on AIX, and works[](#l1.57)
# just fine on other platforms.[](#l1.58)
stdin, stdin_w = self._loop._socketpair()[](#l1.59) if stdout == subprocess.PIPE:[](#l1.60) self._pipes[STDOUT] = None[](#l1.61) if stderr == subprocess.PIPE:[](#l1.62)
@@ -448,6 +466,9 @@ class _UnixSubprocessTransport(transport 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:[](#l1.67)
stdin.close()[](#l1.68)
self._proc.stdin = open(stdin_w.detach(), 'rb', buffering=bufsize)[](#l1.69) self._extra['subprocess'] = self._proc[](#l1.70)
--- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -312,6 +312,13 @@ class UnixReadPipeTransportTests(unittes fcntl_patcher.start() self.addCleanup(fcntl_patcher.stop)
fstat_patcher = unittest.mock.patch('os.fstat')[](#l2.7)
m_fstat = fstat_patcher.start()[](#l2.8)
st = unittest.mock.Mock()[](#l2.9)
st.st_mode = stat.S_IFIFO[](#l2.10)
m_fstat.return_value = st[](#l2.11)
self.addCleanup(fstat_patcher.stop)[](#l2.12)
+ def test_ctor(self): tr = unix_events._UnixReadPipeTransport( self.loop, self.pipe, self.protocol)