bpo-38502: regrtest uses process groups if available (GH-16829) · python/cpython@ecb035c (original) (raw)
`@@ -3,6 +3,7 @@
`
3
3
`import json
`
4
4
`import os
`
5
5
`import queue
`
``
6
`+
import signal
`
6
7
`import subprocess
`
7
8
`import sys
`
8
9
`import threading
`
31
32
`# Time to wait until a worker completes: should be immediate
`
32
33
`JOIN_TIMEOUT = 30.0 # seconds
`
33
34
``
``
35
`+
USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg"))
`
``
36
+
34
37
``
35
38
`def must_stop(result, ns):
`
36
39
`if result.result == INTERRUPTED:
`
`@@ -59,12 +62,16 @@ def run_test_in_subprocess(testname, ns):
`
59
62
`# Running the child from the same working directory as regrtest's original
`
60
63
`# invocation ensures that TEMPDIR for the child is the same when
`
61
64
`# sysconfig.is_python_build() is true. See issue 15300.
`
``
65
`+
kw = {}
`
``
66
`+
if USE_PROCESS_GROUP:
`
``
67
`+
kw['start_new_session'] = True
`
62
68
`return subprocess.Popen(cmd,
`
63
69
`stdout=subprocess.PIPE,
`
64
70
`stderr=subprocess.PIPE,
`
65
71
`universal_newlines=True,
`
66
72
`close_fds=(os.name != 'nt'),
`
67
``
`-
cwd=support.SAVEDCWD)
`
``
73
`+
cwd=support.SAVEDCWD,
`
``
74
`+
**kw)
`
68
75
``
69
76
``
70
77
`def run_tests_worker(ns, test_name):
`
`@@ -149,16 +156,24 @@ def _kill(self):
`
149
156
`return
`
150
157
`self._killed = True
`
151
158
``
152
``
`-
print(f"Kill {self}", file=sys.stderr, flush=True)
`
``
159
`+
if USE_PROCESS_GROUP:
`
``
160
`+
what = f"{self} process group"
`
``
161
`+
else:
`
``
162
`+
what = f"{self}"
`
``
163
+
``
164
`+
print(f"Kill {what}", file=sys.stderr, flush=True)
`
153
165
`try:
`
154
``
`-
popen.kill()
`
``
166
`+
if USE_PROCESS_GROUP:
`
``
167
`+
os.killpg(popen.pid, signal.SIGKILL)
`
``
168
`+
else:
`
``
169
`+
popen.kill()
`
155
170
`except ProcessLookupError:
`
156
``
`-
Process completed, the TestWorkerProcess thread read its exit
`
157
``
`-
status, but Popen.send_signal() read the returncode just before
`
158
``
`-
Popen.wait() set returncode.
`
``
171
`+
popen.kill(): the process completed, the TestWorkerProcess thread
`
``
172
`+
read its exit status, but Popen.send_signal() read the returncode
`
``
173
`+
just before Popen.wait() set returncode.
`
159
174
`pass
`
160
175
`except OSError as exc:
`
161
``
`-
print_warning(f"Failed to kill {self}: {exc!r}")
`
``
176
`+
print_warning(f"Failed to kill {what}: {exc!r}")
`
162
177
``
163
178
`def stop(self):
`
164
179
`# Method called from a different thread to stop this thread
`