[Python-Dev] [Python-checkins] cpython (merge 3.4 -> default): Merge 3.4->default: asyncio: Fix upstream issue 168: StreamReader.read(-1) from
R. David Murray
rdmurray at bitdance.com
Mon May 12 20:43:22 CEST 2014
These changes appear to have caused several builbot failures, and
there doesn't appear to be a bugs.python.org issue to report it to.
One failure example:
http://buildbot.python.org/all/builders/PPC64%20PowerLinux%203.4/builds/119
test_asyncio fails similarly for me on tip.
On Mon, 12 May 2014 19:05:19 +0200, guido.van.rossum <python-checkins at python.org> wrote:
> http://hg.python.org/cpython/rev/2af5a52b9b87
> changeset: 90663:2af5a52b9b87
> parent: 90661:9493fdad2a75
> parent: 90662:909ea8cc86bb
> user: Guido van Rossum <guido at python.org>
> date: Mon May 12 10:05:04 2014 -0700
> summary:
> Merge 3.4->default: asyncio: Fix upstream issue 168: StreamReader.read(-1) from pipe may hang if data exceeds buffer limit.
>
> files:
> Lib/asyncio/streams.py | 17 ++++--
> Lib/test/test_asyncio/test_streams.py | 36 +++++++++++++++
> 2 files changed, 47 insertions(+), 6 deletions(-)
>
>
> diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py
> --- a/Lib/asyncio/streams.py
> +++ b/Lib/asyncio/streams.py
> @@ -419,12 +419,17 @@
> return b''
>
> if n < 0:
> - while not self._eof:
> - self._waiter = self._create_waiter('read')
> - try:
> - yield from self._waiter
> - finally:
> - self._waiter = None
> + # This used to just loop creating a new waiter hoping to
> + # collect everything in self._buffer, but that would
> + # deadlock if the subprocess sends more than self.limit
> + # bytes. So just call self.read(self._limit) until EOF.
> + blocks = []
> + while True:
> + block = yield from self.read(self._limit)
> + if not block:
> + break
> + blocks.append(block)
> + return b''.join(blocks)
> else:
> if not self._buffer and not self._eof:
> self._waiter = self._create_waiter('read')
> diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
> --- a/Lib/test/test_asyncio/test_streams.py
> +++ b/Lib/test/test_asyncio/test_streams.py
> @@ -1,7 +1,9 @@
> """Tests for streams.py."""
>
> import gc
> +import os
> import socket
> +import sys
> import unittest
> from unittest import mock
> try:
> @@ -583,6 +585,40 @@
> server.stop()
> self.assertEqual(msg, b"hello world!\n")
>
> + @unittest.skipIf(sys.platform == 'win32', "Don't have pipes")
> + def test_read_all_from_pipe_reader(self):
> + # See Tulip issue 168. This test is derived from the example
> + # subprocess_attach_read_pipe.py, but we configure the
> + # StreamReader's limit so that twice it is less than the size
> + # of the data writter. Also we must explicitly attach a child
> + # watcher to the event loop.
> +
> + watcher = asyncio.get_child_watcher()
> + watcher.attach_loop(self.loop)
> +
> + code = """\
> +import os, sys
> +fd = int(sys.argv[1])
> +os.write(fd, b'data')
> +os.close(fd)
> +"""
> + rfd, wfd = os.pipe()
> + args = [sys.executable, '-c', code, str(wfd)]
> +
> + pipe = open(rfd, 'rb', 0)
> + reader = asyncio.StreamReader(loop=self.loop, limit=1)
> + protocol = asyncio.StreamReaderProtocol(reader, loop=self.loop)
> + transport, _ = self.loop.run_until_complete(
> + self.loop.connect_read_pipe(lambda: protocol, pipe))
> +
> + proc = self.loop.run_until_complete(
> + asyncio.create_subprocess_exec(*args, pass_fds={wfd}, loop=self.loop))
> + self.loop.run_until_complete(proc.wait())
> +
> + os.close(wfd)
> + data = self.loop.run_until_complete(reader.read(-1))
> + self.assertEqual(data, b'data')
> +
>
> if __name__ == '__main__':
> unittest.main()
>
> --
> Repository URL: http://hg.python.org/cpython
> _______________________________________________
> Python-checkins mailing list
> Python-checkins at python.org
> https://mail.python.org/mailman/listinfo/python-checkins
More information about the Python-Dev
mailing list