From 3845521b4b7b61d49181c611ee427042152671f2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 6 Jan 2014 16:09:18 -0800 Subject: asyncio: Fix deadlock in readexactly(). Fixes issue #20154. --- Lib/asyncio/streams.py | 29 +++++++++++++++++++---------- Misc/NEWS | 2 ++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index 50c4c5d..93a21d1 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -220,6 +220,7 @@ class StreamReader: if loop is None: loop = events.get_event_loop() self._loop = loop + # TODO: Use a bytearray for a buffer, like the transport. self._buffer = collections.deque() # Deque of bytes objects. self._byte_count = 0 # Bytes in buffer. self._eof = False # Whether we're done. @@ -384,15 +385,23 @@ class StreamReader: if self._exception is not None: raise self._exception - if n <= 0: - return b'' + # There used to be "optimized" code here. It created its own + # Future and waited until self._buffer had at least the n + # bytes, then called read(n). Unfortunately, this could pause + # the transport if the argument was larger than the pause + # limit (which is twice self._limit). So now we just read() + # into a local buffer. + + blocks = [] + while n > 0: + block = yield from self.read(n) + if not block: + break + blocks.append(block) + n -= len(block) - while self._byte_count < n and not self._eof: - assert not self._waiter - self._waiter = futures.Future(loop=self._loop) - try: - yield from self._waiter - finally: - self._waiter = None + # TODO: Raise EOFError if we break before n == 0? (That would + # be a change in specification, but I've always had to add an + # explicit size check to the caller.) - return (yield from self.read(n)) + return b''.join(blocks) diff --git a/Misc/NEWS b/Misc/NEWS index 7750233..189e30b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -75,6 +75,8 @@ Core and Builtins Library ------- +- Issue #20154: Deadlock in asyncio.StreamReader.readexactly(). + - Issue #16113: Remove sha3 module again. - Issue #20111: pathlib.Path.with_suffix() now sanity checks the given suffix. -- cgit v0.12