Skip to content

Commit 58498bc

Browse files
authored
bpo-38019: correctly handle pause/resume reading of closed asyncio unix pipe (GH-16472)
1 parent 9a7d951 commit 58498bc

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

Lib/asyncio/unix_events.py

+11
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ def __init__(self, loop, pipe, protocol, waiter=None, extra=None):
445445
self._fileno = pipe.fileno()
446446
self._protocol = protocol
447447
self._closing = False
448+
self._paused = False
448449

449450
mode = os.fstat(self._fileno).st_mode
450451
if not (stat.S_ISFIFO(mode) or
@@ -506,10 +507,20 @@ def _read_ready(self):
506507
self._loop.call_soon(self._call_connection_lost, None)
507508

508509
def pause_reading(self):
510+
if self._closing or self._paused:
511+
return
512+
self._paused = True
509513
self._loop._remove_reader(self._fileno)
514+
if self._loop.get_debug():
515+
logger.debug("%r pauses reading", self)
510516

511517
def resume_reading(self):
518+
if self._closing or not self._paused:
519+
return
520+
self._paused = False
512521
self._loop._add_reader(self._fileno, self._read_ready)
522+
if self._loop.get_debug():
523+
logger.debug("%r resumes reading", self)
513524

514525
def set_protocol(self, protocol):
515526
self._protocol = protocol

Lib/test/test_asyncio/test_unix_events.py

+27
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,7 @@ def test_pause_reading(self, m_read):
736736
@mock.patch('os.read')
737737
def test_resume_reading(self, m_read):
738738
tr = self.read_pipe_transport()
739+
tr.pause_reading()
739740
tr.resume_reading()
740741
self.loop.assert_reader(5, tr._read_ready)
741742

@@ -790,6 +791,32 @@ def test__call_connection_lost_with_err(self):
790791
self.assertIsNone(tr._protocol)
791792
self.assertIsNone(tr._loop)
792793

794+
def test_pause_reading_on_closed_pipe(self):
795+
tr = self.read_pipe_transport()
796+
tr.close()
797+
test_utils.run_briefly(self.loop)
798+
self.assertIsNone(tr._loop)
799+
tr.pause_reading()
800+
801+
def test_pause_reading_on_paused_pipe(self):
802+
tr = self.read_pipe_transport()
803+
tr.pause_reading()
804+
# the second call should do nothing
805+
tr.pause_reading()
806+
807+
def test_resume_reading_on_closed_pipe(self):
808+
tr = self.read_pipe_transport()
809+
tr.close()
810+
test_utils.run_briefly(self.loop)
811+
self.assertIsNone(tr._loop)
812+
tr.resume_reading()
813+
814+
def test_resume_reading_on_paused_pipe(self):
815+
tr = self.read_pipe_transport()
816+
# the pipe is not paused
817+
# resuming should do nothing
818+
tr.resume_reading()
819+
793820

794821
class UnixWritePipeTransportTests(test_utils.TestCase):
795822

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

0 commit comments

Comments
 (0)