diff options
author | Guido van Rossum <guido@python.org> | 2014-01-07 00:09:18 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2014-01-07 00:09:18 (GMT) |
commit | 3845521b4b7b61d49181c611ee427042152671f2 (patch) | |
tree | 252edcd3a6edc003c28ea09b7f93fccfc3ed026f /Lib/asyncio | |
parent | a101bdb88c064c77e7322063fac1a2f24a60b32b (diff) | |
download | cpython-3845521b4b7b61d49181c611ee427042152671f2.zip cpython-3845521b4b7b61d49181c611ee427042152671f2.tar.gz cpython-3845521b4b7b61d49181c611ee427042152671f2.tar.bz2 |
asyncio: Fix deadlock in readexactly(). Fixes issue #20154.
Diffstat (limited to 'Lib/asyncio')
-rw-r--r-- | Lib/asyncio/streams.py | 29 |
1 files changed, 19 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) |