Skip to content

Commit 20c0f9c

Browse files
authored
Merge pull request #2363 from willend/main
mctest / timeout system - ensure to kill underlying processes
2 parents 71bfc59 + c019989 commit 20c0f9c

1 file changed

Lines changed: 25 additions & 7 deletions

File tree

tools/Python/mccodelib/utils.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
'''
44
import re
55
import os
6+
import sys
67
from os.path import splitext, join
78
import subprocess
89
from datetime import datetime
@@ -773,13 +774,21 @@ def get_file_contents(filepath):
773774
return ''
774775

775776
def run_subtool_noread(cmd, cwd=None, timeout=None):
776-
"""Run external command without reading output; kill if it runs longer than timeout (seconds).
777+
"""Run external command without reading output; kill whole process group on timeout.
777778
Returns (returncode, timed_out: bool).
778779
"""
779780

780781
if not cwd:
781782
cwd = os.getcwd()
782783

784+
# Platform-specific flags
785+
if sys.platform == "win32":
786+
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP
787+
preexec_fn = None
788+
else:
789+
creationflags = 0
790+
preexec_fn = os.setsid # start new session -> new process group
791+
783792
try:
784793
process = subprocess.Popen(
785794
cmd,
@@ -789,21 +798,30 @@ def run_subtool_noread(cmd, cwd=None, timeout=None):
789798
shell=True,
790799
universal_newlines=True,
791800
cwd=cwd,
801+
preexec_fn=preexec_fn,
802+
creationflags=creationflags,
792803
)
793804

794805
try:
795-
# communicate supports timeout (Python 3.3+)
796806
process.communicate(timeout=timeout)
797807
return process.returncode, False
798808
except subprocess.TimeoutExpired:
799-
# force kill if still alive
809+
# Kill the whole process group
800810
try:
801-
process.kill() # SIGKILL on Unix
811+
if sys.platform == "win32":
812+
# send CTRL_BREAK_EVENT to the process group
813+
process.send_signal(signal.CTRL_BREAK_EVENT)
814+
else:
815+
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
802816
except Exception:
803-
pass
817+
# fallback to killing the process
818+
try:
819+
process.kill()
820+
except Exception:
821+
pass
822+
# Wait for termination
804823
process.wait()
805-
806-
return process.returncode if process.returncode is not None else -1, True
824+
return process.returncode if process.returncode is not None else -1, True
807825

808826
except Exception as e:
809827
# unicode/read error safe-guard

0 commit comments

Comments
 (0)