summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2014-01-07 00:09:18 (GMT)
committerGuido van Rossum <guido@python.org>2014-01-07 00:09:18 (GMT)
commit3845521b4b7b61d49181c611ee427042152671f2 (patch)
tree252edcd3a6edc003c28ea09b7f93fccfc3ed026f /Lib/asyncio
parenta101bdb88c064c77e7322063fac1a2f24a60b32b (diff)
downloadcpython-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.py29
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)