11import socket
22import asyncio
3+ import select
34import sys
45import unittest
56
@@ -257,6 +258,38 @@ async def _basetest_sock_connect_racing(self, listener, sock):
257258
258259 self .skipTest (skip_reason )
259260
261+ async def _basetest_sock_accept_racing (self , listener , sock ):
262+ # gh-153761: cancelling sock_accept() must not let a scheduled
263+ # _sock_accept run on the cancelled future.
264+ listener .setblocking (False )
265+ listener .bind (('127.0.0.1' , 0 ))
266+ listener .listen (1 )
267+ addr = listener .getsockname ()
268+
269+ errors = []
270+ self .loop .set_exception_handler (lambda loop , ctx : errors .append (ctx ))
271+ task = asyncio .create_task (self .loop .sock_accept (listener ))
272+ await asyncio .sleep (0 )
273+
274+ sock .connect (addr )
275+ select .select ([listener ], [], [], support .SHORT_TIMEOUT )
276+
277+ self .loop .call_soon (task .cancel )
278+ await asyncio .sleep (0 )
279+ await asyncio .sleep (0 )
280+
281+ with self .assertRaises (asyncio .CancelledError ):
282+ await task
283+ self .assertEqual (errors , [])
284+
285+ # The pending connection must survive
286+ conn , conn_addr = await self .loop .sock_accept (listener )
287+ with conn :
288+ self .assertEqual (conn_addr , sock .getsockname ())
289+ sock .setblocking (False )
290+ await self .loop .sock_sendall (conn , b'ping' )
291+ self .assertEqual (await self .loop .sock_recv (sock , 4 ), b'ping' )
292+
260293 def test_sock_client_racing (self ):
261294 with test_utils .run_test_server () as httpd :
262295 sock = socket .socket ()
@@ -280,6 +313,16 @@ def test_sock_client_connect_racing(self):
280313 self .loop .run_until_complete (asyncio .wait_for (
281314 self ._basetest_sock_connect_racing (listener , sock ), 10 ))
282315
316+ def test_sock_accept_racing (self ):
317+ if sys .platform == 'win32' :
318+ if isinstance (self .loop , asyncio .ProactorEventLoop ):
319+ raise unittest .SkipTest ('Not relevant to ProactorEventLoop' )
320+ listener = socket .socket ()
321+ sock = socket .socket ()
322+ with listener , sock :
323+ self .loop .run_until_complete (asyncio .wait_for (
324+ self ._basetest_sock_accept_racing (listener , sock ), 10 ))
325+
283326 async def _basetest_huge_content (self , address ):
284327 sock = socket .socket ()
285328 sock .setblocking (False )
0 commit comments