mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
asyncio, tulip issue 209: Fix subprocess for close_fds=False on Python 3.3
Mark the write end of the stdin pipe as non-inheritable.
This commit is contained in:
parent
df75d5b402
commit
1e40f10886
2 changed files with 43 additions and 0 deletions
|
@ -547,6 +547,22 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
|
||||||
self._loop = None
|
self._loop = None
|
||||||
|
|
||||||
|
|
||||||
|
if hasattr(os, 'set_inheritable'):
|
||||||
|
# Python 3.4 and newer
|
||||||
|
_set_inheritable = os.set_inheritable
|
||||||
|
else:
|
||||||
|
import fcntl
|
||||||
|
|
||||||
|
def _set_inheritable(fd, inheritable):
|
||||||
|
cloexec_flag = getattr(fcntl, 'FD_CLOEXEC', 1)
|
||||||
|
|
||||||
|
old = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||||
|
if not inheritable:
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
|
||||||
|
else:
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag)
|
||||||
|
|
||||||
|
|
||||||
class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport):
|
class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport):
|
||||||
|
|
||||||
def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
|
def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs):
|
||||||
|
@ -558,6 +574,12 @@ class _UnixSubprocessTransport(base_subprocess.BaseSubprocessTransport):
|
||||||
# other end). Notably this is needed on AIX, and works
|
# other end). Notably this is needed on AIX, and works
|
||||||
# just fine on other platforms.
|
# just fine on other platforms.
|
||||||
stdin, stdin_w = self._loop._socketpair()
|
stdin, stdin_w = self._loop._socketpair()
|
||||||
|
|
||||||
|
# Mark the write end of the stdin pipe as non-inheritable,
|
||||||
|
# needed by close_fds=False on Python 3.3 and older
|
||||||
|
# (Python 3.4 implements the PEP 446, socketpair returns
|
||||||
|
# non-inheritable sockets)
|
||||||
|
_set_inheritable(stdin_w.fileno(), False)
|
||||||
self._proc = subprocess.Popen(
|
self._proc = subprocess.Popen(
|
||||||
args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr,
|
args, shell=shell, stdin=stdin, stdout=stdout, stderr=stderr,
|
||||||
universal_newlines=False, bufsize=bufsize, **kwargs)
|
universal_newlines=False, bufsize=bufsize, **kwargs)
|
||||||
|
|
|
@ -198,6 +198,27 @@ class SubprocessMixin:
|
||||||
self.assertTrue(transport.pause_reading.called)
|
self.assertTrue(transport.pause_reading.called)
|
||||||
self.assertTrue(transport.resume_reading.called)
|
self.assertTrue(transport.resume_reading.called)
|
||||||
|
|
||||||
|
def test_stdin_not_inheritable(self):
|
||||||
|
# Tulip issue #209: stdin must not be inheritable, otherwise
|
||||||
|
# the Process.communicate() hangs
|
||||||
|
@asyncio.coroutine
|
||||||
|
def len_message(message):
|
||||||
|
code = 'import sys; data = sys.stdin.read(); print(len(data))'
|
||||||
|
proc = yield from asyncio.create_subprocess_exec(
|
||||||
|
sys.executable, '-c', code,
|
||||||
|
stdin=asyncio.subprocess.PIPE,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE,
|
||||||
|
close_fds=False,
|
||||||
|
loop=self.loop)
|
||||||
|
stdout, stderr = yield from proc.communicate(message)
|
||||||
|
exitcode = yield from proc.wait()
|
||||||
|
return (stdout, exitcode)
|
||||||
|
|
||||||
|
output, exitcode = self.loop.run_until_complete(len_message(b'abc'))
|
||||||
|
self.assertEqual(output.rstrip(), b'3')
|
||||||
|
self.assertEqual(exitcode, 0)
|
||||||
|
|
||||||
|
|
||||||
if sys.platform != 'win32':
|
if sys.platform != 'win32':
|
||||||
# Unix
|
# Unix
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue