Skip to content

Commit efe83ad

Browse files
[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 bd4518c) Co-authored-by: Victor Stinner <[email protected]>
1 parent a997295 commit efe83ad

File tree

3 files changed

+17
-4
lines changed

3 files changed

+17
-4
lines changed

Lib/multiprocessing/popen_spawn_win32.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#
1515
#
1616

17+
# Exit code used by Popen.terminate()
1718
TERMINATE = 0x10000
1819
WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
1920
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
@@ -122,9 +123,15 @@ def terminate(self):
122123
if self.returncode is None:
123124
try:
124125
_winapi.TerminateProcess(int(self._handle), TERMINATE)
125-
except OSError:
126-
if self.wait(timeout=1.0) is None:
126+
except PermissionError:
127+
# ERROR_ACCESS_DENIED (winerror 5) is received when the
128+
# process already died.
129+
code = _winapi.GetExitCodeProcess(int(self._handle))
130+
if code == _winapi.STILL_ACTIVE:
127131
raise
132+
self.returncode = code
133+
else:
134+
self.returncode = -signal.SIGTERM
128135

129136
kill = terminate
130137

Lib/test/_test_multiprocessing.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -556,13 +556,14 @@ def handler(*args):
556556

557557
def test_terminate(self):
558558
exitcode = self._kill_process(multiprocessing.Process.terminate)
559-
if os.name != 'nt':
560-
self.assertEqual(exitcode, -signal.SIGTERM)
559+
self.assertEqual(exitcode, -signal.SIGTERM)
561560

562561
def test_kill(self):
563562
exitcode = self._kill_process(multiprocessing.Process.kill)
564563
if os.name != 'nt':
565564
self.assertEqual(exitcode, -signal.SIGKILL)
565+
else:
566+
self.assertEqual(exitcode, -signal.SIGTERM)
566567

567568
def test_cpu_count(self):
568569
try:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
On Windows, multiprocessing ``Popen.terminate()`` now catchs
2+
:exc:`PermissionError` and get the process exit code. If the process is
3+
still running, raise again the :exc:`PermissionError`. Otherwise, the
4+
process terminated as expected: store its exit code. Patch by Victor
5+
Stinner.

0 commit comments

Comments
 (0)