8000 bpo-39010: Fix errors logged on proactor loop restart (#22017) · python/cpython@ea5a636 · GitHub
[go: up one dir, main page]

Skip to content

Commit ea5a636

Browse files
authored
bpo-39010: Fix errors logged on proactor loop restart (#22017)
Stopping and restarting a proactor event loop on windows can lead to spurious errors logged (ConnectionResetError while reading from the self pipe). This fixes the issue by ensuring that we don't attempt to start multiple copies of the self-pipe reading loop.
1 parent c3a651a commit ea5a636

File tree

5 files changed

+37
-2
lines changed

5 files changed

+37
-2
lines changed

Lib/asyncio/proactor_events.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,14 @@ def _loop_self_reading(self, f=None):
768768
try:
769769
if f is not None:
770770
f.result() # may raise
771+
if self._self_reading_future is not f:
772+
# When we scheduled this Future, we assigned it to
773+
# _self_reading_future. If it's not there now, something has
774+
# tried to cancel the loop while this callback was still in the
775+
# queue (see windows_events.ProactorEventLoop.run_forever). In
776+
# that case stop here instead of continuing to schedule a new
777+
# iteration.
778+
return
771779
f = self._proactor.recv(self._ssock, 4096)
772780
except exceptions.CancelledError:
773781
# _close_self_pipe() has been called, stop waiting for data

Lib/asyncio/windows_events.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,12 @@ def run_forever(self):
318318
if self._self_reading_future is not None:
319319
ov = self._self_reading_future._ov
320320
self._self_reading_future.cancel()
321-
# self_reading_future was just cancelled so it will never be signalled
322-
# Unregister it otherwise IocpProactor.close will wait for it forever
321+
# self_reading_future was just cancelled so if it hasn't been
322+
# finished yet, it never will be (it's possible that it has
323+
# already finished and its callback is waiting in the queue,
324+
# where it could still happen if the event loop is restarted).
325+
# Unregister it otherwise IocpProactor.close will wait for it
326+
# forever
323327
if ov is not None:
324328
self._proactor._unregister(ov)
325329
self._self_reading_future = None

Lib/test/test_asyncio/test_proactor_events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ def test_loop_self_reading(self):
753753

754754
def test_loop_self_reading_fut(self):
755755
fut = mock.Mock()
756+
self.loop._self_reading_future = fut
756757
self.loop._loop_self_reading(fut)
757758
self.assertTrue(fut.result.called)
758759
self.proactor.recv.assert_called_with(self.ssock, 4096)

Lib/test/test_asyncio/test_windows_events.py

Lines changed: 20 additions & 0 deletions
< 8000 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,26 @@ def test_wait_for_handle_cancel(self):
211211
fut.cancel()
212212
fut.cancel()
213213

214+
def test_read_self_pipe_restart(self):
215+
# Regression test for https://bugs.python.org/issue39010
216+
# Previously, restarting a proactor event loop in certain states
217+
# would lead to spurious ConnectionResetErrors being logged.
218+
self.loop.call_exception_handler = mock.Mock()
219+
# Start an operation in another thread so that the self-pipe is used.
220+
# This is theoretically timing-dependent (the task in the executor
221+
# must complete before our start/stop cycles), but in practice it
222+
# seems to work every time.
223+
f = self.loop.run_in_executor(None, lambda: None)
224+
self.loop.stop()
225+
self.loop.run_forever()
226+
self.loop.stop()
227+
self.loop.run_forever()
228+
# If we don't wait for f to complete here, we may get another
229+
# warning logged about a thread that didn't shut down cleanly.
230+
self.loop.run_until_complete(f)
231+
self.loop.close()
232+
self.assertFalse(self.loop.call_exception_handler.called)
233+
214234

215235
class WinPolicyTests(test_utils.TestCase):
216236

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Restarting a ``ProactorEventLoop`` on Windows no longer logs spurious
2+
``ConnectionResetErrors``.

0 commit comments

Comments
 (0)
0