diff --git a/Lib/test/test_dtrace.py b/Lib/test/test_dtrace.py index 6286b6d21b572e..5ade826756b7c9 100644 --- a/Lib/test/test_dtrace.py +++ b/Lib/test/test_dtrace.py @@ -1,6 +1,7 @@ import dis import os.path import re +import signal import subprocess import sys import sysconfig @@ -50,6 +51,20 @@ def normalize_trace_output(output): ) +USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) + +def create_process_group(*args, **kwargs): + if USE_PROCESS_GROUP: + kwargs['start_new_session'] = True + return subprocess.Popen(*args, **kwargs) + +def kill_process_group(proc): + if USE_PROCESS_GROUP: + os.killpg(proc.pid, signal.SIGKILL) + else: + proc.kill() + + class TraceBackend: EXTENSION = None COMMAND = None @@ -205,7 +220,7 @@ def run_case(self, name, optimize_python=None): program = self.PROGRAMS[name].format(python=sys.executable) try: - proc = subprocess.Popen( + proc = create_process_group( ["bpftrace", "-e", program, "-c", " ".join(subcommand)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -213,7 +228,7 @@ def run_case(self, name, optimize_python=None): ) stdout, stderr = proc.communicate(timeout=60) except subprocess.TimeoutExpired: - proc.kill() + kill_process_group(proc) raise AssertionError("bpftrace timed out") except (FileNotFoundError, PermissionError) as e: raise unittest.SkipTest(f"bpftrace not available: {e}") @@ -243,7 +258,7 @@ def assert_usable(self): # Check if bpftrace is available and can attach to USDT probes program = f'usdt:{sys.executable}:python:function__entry {{ printf("probe: success\\n"); exit(); }}' try: - proc = subprocess.Popen( + proc = create_process_group( ["bpftrace", "-e", program, "-c", f"{sys.executable} -c pass"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -251,7 +266,7 @@ def assert_usable(self): ) stdout, stderr = proc.communicate(timeout=10) except subprocess.TimeoutExpired: - proc.kill() + kill_process_group(proc) proc.communicate() # Clean up raise unittest.SkipTest("bpftrace timed out during usability check") except OSError as e: