From 54bbc06b0b1b6bec32af3492815f1da17fdf04b9 Mon Sep 17 00:00:00 2001 From: Keuin Date: Mon, 5 Jun 2023 02:42:07 +0800 Subject: [PATCH] gh-105288: wake up exit waiters after sub-process exits --- Lib/asyncio/base_subprocess.py | 14 +++++++++----- .../2023-06-05-02-48-08.gh-issue-105288.Ewnyas.rst | 3 +++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-06-05-02-48-08.gh-issue-105288.Ewnyas.rst diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 4c9b0dd5653c0c5..d64c31d535a7dd9 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -217,6 +217,14 @@ def _process_exited(self, returncode): self._call(self._protocol.process_exited) self._try_finish() + self._wakeup_exit_waiters() + + def _wakeup_exit_waiters(self): + # wake up futures waiting for wait() + for waiter in self._exit_waiters: + if not waiter.cancelled(): + waiter.set_result(self._returncode) + self._exit_waiters = [] async def _wait(self): """Wait until the process exit and return the process return code. @@ -242,11 +250,7 @@ def _call_connection_lost(self, exc): try: self._protocol.connection_lost(exc) finally: - # wake up futures waiting for wait() - for waiter in self._exit_waiters: - if not waiter.cancelled(): - waiter.set_result(self._returncode) - self._exit_waiters = None + self._wakeup_exit_waiters() self._loop = None self._proc = None self._protocol = None diff --git a/Misc/NEWS.d/next/Library/2023-06-05-02-48-08.gh-issue-105288.Ewnyas.rst b/Misc/NEWS.d/next/Library/2023-06-05-02-48-08.gh-issue-105288.Ewnyas.rst new file mode 100644 index 000000000000000..031557bb1281232 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-05-02-48-08.gh-issue-105288.Ewnyas.rst @@ -0,0 +1,3 @@ +Exit waiters are not resolved after subprocess handled by :class:`asyncio.Task` +exits. This will causes a recent :func:`asyncio.wait` call hang forever if there +are objects that are not :type:`Awaitable` yield from its first parameter.