diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2023-09-29 01:04:58 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-29 01:04:58 (GMT) |
commit | efe83ad2762e3ea8b396b44947033445c9b31d04 (patch) | |
tree | 2afbd62f9879f13257ad97e035728cd161c3fd47 | |
parent | a99729599a70d73e8796f6c9d5cdf6807bda0cd5 (diff) | |
download | cpython-efe83ad2762e3ea8b396b44947033445c9b31d04.zip cpython-efe83ad2762e3ea8b396b44947033445c9b31d04.tar.gz cpython-efe83ad2762e3ea8b396b44947033445c9b31d04.tar.bz2 |
[3.11] gh-110036: multiprocessing Popen.terminate() catches PermissionError (GH-110037) (#110065)
gh-110036: multiprocessing Popen.terminate() catches PermissionError (GH-110037)
On Windows, multiprocessing Popen.terminate() now catchs
PermissionError and get the process exit code. If the process is
still running, raise again the PermissionError. Otherwise, the
process terminated as expected: store its exit code.
(cherry picked from commit bd4518c60c9df356cf5e05b81305e3644ebb5e70)
Co-authored-by: Victor Stinner <vstinner@python.org>
-rw-r--r-- | Lib/multiprocessing/popen_spawn_win32.py | 11 | ||||
-rw-r--r-- | Lib/test/_test_multiprocessing.py | 5 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst | 5 |
3 files changed, 17 insertions, 4 deletions
diff --git a/Lib/multiprocessing/popen_spawn_win32.py b/Lib/multiprocessing/popen_spawn_win32.py index 4d60ffc..af04430 100644 --- a/Lib/multiprocessing/popen_spawn_win32.py +++ b/Lib/multiprocessing/popen_spawn_win32.py @@ -14,6 +14,7 @@ __all__ = ['Popen'] # # +# Exit code used by Popen.terminate() TERMINATE = 0x10000 WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False)) WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") @@ -122,9 +123,15 @@ class Popen(object): if self.returncode is None: try: _winapi.TerminateProcess(int(self._handle), TERMINATE) - except OSError: - if self.wait(timeout=1.0) is None: + except PermissionError: + # ERROR_ACCESS_DENIED (winerror 5) is received when the + # process already died. + code = _winapi.GetExitCodeProcess(int(self._handle)) + if code == _winapi.STILL_ACTIVE: raise + self.returncode = code + else: + self.returncode = -signal.SIGTERM kill = terminate diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index c3ba1f6..6249062 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -556,13 +556,14 @@ class _TestProcess(BaseTestCase): def test_terminate(self): exitcode = self._kill_process(multiprocessing.Process.terminate) - if os.name != 'nt': - self.assertEqual(exitcode, -signal.SIGTERM) + self.assertEqual(exitcode, -signal.SIGTERM) def test_kill(self): exitcode = self._kill_process(multiprocessing.Process.kill) if os.name != 'nt': self.assertEqual(exitcode, -signal.SIGKILL) + else: + self.assertEqual(exitcode, -signal.SIGTERM) def test_cpu_count(self): try: diff --git a/Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst b/Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst new file mode 100644 index 0000000..ddb11b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-09-28-18-53-11.gh-issue-110036.fECxTj.rst @@ -0,0 +1,5 @@ +On Windows, multiprocessing ``Popen.terminate()`` now catchs +:exc:`PermissionError` and get the process exit code. If the process is +still running, raise again the :exc:`PermissionError`. Otherwise, the +process terminated as expected: store its exit code. Patch by Victor +Stinner. |