@@ -62,13 +62,18 @@ def _handle_wait_complete(_: asyncio.Task) -> None:
6262 await event_wait
6363
6464
65- async def _get_all_tasks (loop : asyncio .AbstractEventLoop ) -> List [asyncio .Task ]:
65+ async def _async_get_all_tasks (loop : asyncio .AbstractEventLoop ) -> List [asyncio .Task ]:
6666 """Return all tasks running."""
6767 await asyncio .sleep (0 ) # flush out any call_soon_threadsafe
68- # Make a copy of the tasks in case they change during iteration
69- if hasattr (asyncio , 'all_tasks' ):
70- return list (asyncio .all_tasks (loop )) # type: ignore # pylint: disable=no-member
71- return list (asyncio .Task .all_tasks (loop )) # type: ignore # pylint: disable=no-member
68+ # If there are multiple event loops running, all_tasks is not
69+ # safe EVEN WHEN CALLED FROM THE EVENTLOOP
70+ # under PyPy so we have to try a few times.
71+ for _ in range (3 ):
72+ with contextlib .suppress (RuntimeError ):
73+ if hasattr (asyncio , 'all_tasks' ):
74+ return asyncio .all_tasks (loop ) # type: ignore # pylint: disable=no-member
75+ return asyncio .Task .all_tasks (loop ) # type: ignore # pylint: disable=no-member
76+ return []
7277
7378
7479async def _wait_for_loop_tasks (wait_tasks : Set [asyncio .Task ]) -> None :
@@ -78,7 +83,7 @@ async def _wait_for_loop_tasks(wait_tasks: Set[asyncio.Task]) -> None:
7883
7984def shutdown_loop (loop : asyncio .AbstractEventLoop ) -> None :
8085 """Wait for pending tasks and stop an event loop."""
81- pending_tasks = set (asyncio .run_coroutine_threadsafe (_get_all_tasks (loop ), loop ).result ())
86+ pending_tasks = set (asyncio .run_coroutine_threadsafe (_async_get_all_tasks (loop ), loop ).result ())
8287 done_tasks = set (task for task in pending_tasks if not task .done ())
8388 pending_tasks -= done_tasks
8489 if pending_tasks :
0 commit comments