diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py index 6dbde2b696ad1f..ca675a1646f09c 100644 --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -1,6 +1,8 @@ import collections import subprocess import warnings +import os +import signal from . import protocols from . import transports @@ -144,15 +146,16 @@ def _check_proc(self): def send_signal(self, signal): self._check_proc() - self._proc.send_signal(signal) + try: + os.kill(self._proc.pid, signal) + except ProcessLookupError: + pass def terminate(self): - self._check_proc() - self._proc.terminate() + self.send_signal(signal.SIGTERM) def kill(self): - self._check_proc() - self._proc.kill() + self.send_signal(signal.SIGKILL) async def _connect_pipes(self, waiter): try: diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py index 23987c70ca7b63..e38c6eab4a4f00 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py @@ -864,6 +864,20 @@ async def main(): self.loop.run_until_complete(main()) + def test_subprocess_send_signal_race(self): + # See https://github.com/python/cpython/issues/87744 + async def main(): + for _ in range(10): + proc = await asyncio.create_subprocess_exec('sleep', '0.1') + await asyncio.sleep(0.1) + try: + proc.send_signal(signal.SIGUSR1) + except ProcessLookupError: + pass + self.assertNotEqual(await proc.wait(), 255) + + self.loop.run_until_complete(main()) + if sys.platform != 'win32': # Unix