diff options
author | Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> | 2022-10-05 17:15:31 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-05 17:15:31 (GMT) |
commit | 7015e1379791cbf19908cd1a7c668a5d6e7165d5 (patch) | |
tree | 1bd888e4ba361d3fab3dc95d5b550bdc22a76c04 /Lib | |
parent | 0e72606dd4cf3023a4f8c2fe3c58082592b253f7 (diff) | |
download | cpython-7015e1379791cbf19908cd1a7c668a5d6e7165d5.zip cpython-7015e1379791cbf19908cd1a7c668a5d6e7165d5.tar.gz cpython-7015e1379791cbf19908cd1a7c668a5d6e7165d5.tar.bz2 |
gh-88050: Fix asyncio subprocess to kill process cleanly when process is blocked (#32073)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/asyncio/base_subprocess.py | 13 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_subprocess.py | 25 |
2 files changed, 32 insertions, 6 deletions
diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 14d5051..c2ca4a2 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -215,14 +215,10 @@ class BaseSubprocessTransport(transports.SubprocessTransport): # object. On Python 3.6, it is required to avoid a ResourceWarning. self._proc.returncode = returncode self._call(self._protocol.process_exited) + for p in self._pipes.values(): + p.pipe.close() self._try_finish() - # wake up futures waiting for wait() - for waiter in self._exit_waiters: - if not waiter.cancelled(): - waiter.set_result(returncode) - self._exit_waiters = None - async def _wait(self): """Wait until the process exit and return the process return code. @@ -247,6 +243,11 @@ class BaseSubprocessTransport(transports.SubprocessTransport): 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._loop = None self._proc = None self._protocol = None diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 961c463..9bc60b9 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -1,4 +1,5 @@ import os +import shutil import signal import sys import unittest @@ -182,6 +183,30 @@ class SubprocessMixin: else: self.assertEqual(-signal.SIGKILL, returncode) + def test_kill_issue43884(self): + blocking_shell_command = f'{sys.executable} -c "import time; time.sleep(100000000)"' + creationflags = 0 + if sys.platform == 'win32': + from subprocess import CREATE_NEW_PROCESS_GROUP + # On windows create a new process group so that killing process + # kills the process and all its children. + creationflags = CREATE_NEW_PROCESS_GROUP + proc = self.loop.run_until_complete( + asyncio.create_subprocess_shell(blocking_shell_command, stdout=asyncio.subprocess.PIPE, + creationflags=creationflags) + ) + self.loop.run_until_complete(asyncio.sleep(1)) + if sys.platform == 'win32': + proc.send_signal(signal.CTRL_BREAK_EVENT) + # On windows it is an alias of terminate which sets the return code + proc.kill() + returncode = self.loop.run_until_complete(proc.wait()) + if sys.platform == 'win32': + self.assertIsInstance(returncode, int) + # expect 1 but sometimes get 0 + else: + self.assertEqual(-signal.SIGKILL, returncode) + def test_terminate(self): args = PROGRAM_BLOCKED proc = self.loop.run_until_complete( |