Skip to content

Commit

Permalink
bpo-38019: correctly handle pause/resume reading of closed asyncio un…
Browse files Browse the repository at this point in the history
…ix pipe (GH-16472)

(cherry picked from commit 58498bc)

Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
  • Loading branch information
miss-islington and asvetlov committed Sep 29, 2019
1 parent 80dd66a commit 1c3e469
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Lib/asyncio/unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
self._fileno = pipe.fileno()
self._protocol = protocol
self._closing = False
self._paused = False

mode = os.fstat(self._fileno).st_mode
if not (stat.S_ISFIFO(mode) or
Expand Down Expand Up @@ -492,10 +493,20 @@ def _read_ready(self):
self._loop.call_soon(self._call_connection_lost, None)

def pause_reading(self):
if self._closing or self._paused:
return
self._paused = True
self._loop._remove_reader(self._fileno)
if self._loop.get_debug():
logger.debug("%r pauses reading", self)

def resume_reading(self):
if self._closing or not self._paused:
return
self._paused = False
self._loop._add_reader(self._fileno, self._read_ready)
if self._loop.get_debug():
logger.debug("%r resumes reading", self)

def set_protocol(self, protocol):
self._protocol = protocol
Expand Down
27 changes: 27 additions & 0 deletions Lib/test/test_asyncio/test_unix_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ def test_pause_reading(self, m_read):
@mock.patch('os.read')
def test_resume_reading(self, m_read):
tr = self.read_pipe_transport()
tr.pause_reading()
tr.resume_reading()
self.loop.assert_reader(5, tr._read_ready)

Expand Down Expand Up @@ -776,6 +777,32 @@ def test__call_connection_lost_with_err(self):
self.assertIsNone(tr._protocol)
self.assertIsNone(tr._loop)

def test_pause_reading_on_closed_pipe(self):
tr = self.read_pipe_transport()
tr.close()
test_utils.run_briefly(self.loop)
self.assertIsNone(tr._loop)
tr.pause_reading()

def test_pause_reading_on_paused_pipe(self):
tr = self.read_pipe_transport()
tr.pause_reading()
# the second call should do nothing
tr.pause_reading()

def test_resume_reading_on_closed_pipe(self):
tr = self.read_pipe_transport()
tr.close()
test_utils.run_briefly(self.loop)
self.assertIsNone(tr._loop)
tr.resume_reading()

def test_resume_reading_on_paused_pipe(self):
tr = self.read_pipe_transport()
# the pipe is not paused
# resuming should do nothing
tr.resume_reading()


class UnixWritePipeTransportTests(test_utils.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Correctly handle pause/resume reading of closed asyncio unix pipe.

0 comments on commit 1c3e469

Please sign in to comment.