Skip to content

Commit 4ff8e5b

Browse files
bpo-41317: Remove reader on cancellation in asyncio.loop.sock_accept() (GH-21595)
(cherry picked from commit 0dd98c2) Co-authored-by: Alex Grönholm <[email protected]>
1 parent e8dda90 commit 4ff8e5b

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

Lib/asyncio/selector_events.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -555,20 +555,19 @@ async def sock_accept(self, sock):
555555
if self._debug and sock.gettimeout() != 0:
556556
raise ValueError("the socket must be non-blocking")
557557
fut = self.create_future()
558-
self._sock_accept(fut, False, sock)
558+
self._sock_accept(fut, sock)
559559
return await fut
560560

561-
def _sock_accept(self, fut, registered, sock):
561+
def _sock_accept(self, fut, sock):
562562
fd = sock.fileno()
563-
if registered:
564-
self.remove_reader(fd)
565-
if fut.done():
566-
return
567563
try:
568564
conn, address = sock.accept()
569565
conn.setblocking(False)
570566
except (BlockingIOError, InterruptedError):
571-
self.add_reader(fd, self._sock_accept, fut, True, sock)
567+
self._ensure_fd_no_transport(fd)
568+
handle = self._add_reader(fd, self._sock_accept, fut, sock)
569+
fut.add_done_callback(
570+
functools.partial(self._sock_read_done, fd, handle=handle))
572571
except (SystemExit, KeyboardInterrupt):
573572
raise
574573
except BaseException as exc:

Lib/test/test_asyncio/test_sock_lowlevel.py

+19
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,25 @@ def test_sock_accept(self):
415415
conn.close()
416416
listener.close()
417417

418+
def test_cancel_sock_accept(self):
419+
listener = socket.socket()
420+
listener.setblocking(False)
421+
listener.bind(('127.0.0.1', 0))
422+
listener.listen(1)
423+
sockaddr = listener.getsockname()
424+
f = asyncio.wait_for(self.loop.sock_accept(listener), 0.1)
425+
with self.assertRaises(asyncio.TimeoutError):
426+
self.loop.run_until_complete(f)
427+
428+
listener.close()
429+
client = socket.socket()
430+
client.setblocking(False)
431+
f = self.loop.sock_connect(client, sockaddr)
432+
with self.assertRaises(ConnectionRefusedError):
433+
self.loop.run_until_complete(f)
434+
435+
client.close()
436+
418437
def test_create_connection_sock(self):
419438
with test_utils.run_test_server() as httpd:
420439
sock = None
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Use add_done_callback() in asyncio.loop.sock_accept() to unsubscribe reader
2+
early on cancellation.

0 commit comments

Comments
 (0)