|
1 | 1 | import dis |
2 | 2 | import os.path |
3 | 3 | import re |
| 4 | +import signal |
4 | 5 | import subprocess |
5 | 6 | import sys |
6 | 7 | import sysconfig |
@@ -50,6 +51,26 @@ def normalize_trace_output(output): |
50 | 51 | ) |
51 | 52 |
|
52 | 53 |
|
| 54 | +USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg")) |
| 55 | + |
| 56 | +def create_process_group(*args, **kwargs): |
| 57 | + if USE_PROCESS_GROUP: |
| 58 | + kwargs['start_new_session'] = True |
| 59 | + return subprocess.Popen(*args, **kwargs) |
| 60 | + |
| 61 | +def kill_process_group(proc): |
| 62 | + use_killpg = USE_PROCESS_GROUP |
| 63 | + if use_killpg: |
| 64 | + parent_sid = os.getsid(0) |
| 65 | + sid = os.getsid(proc.pid) |
| 66 | + use_killpg = (sid != parent_sid) |
| 67 | + |
| 68 | + if use_killpg: |
| 69 | + os.killpg(proc.pid, signal.SIGKILL) |
| 70 | + else: |
| 71 | + proc.kill() |
| 72 | + |
| 73 | + |
53 | 74 | class TraceBackend: |
54 | 75 | EXTENSION = None |
55 | 76 | COMMAND = None |
@@ -205,15 +226,15 @@ def run_case(self, name, optimize_python=None): |
205 | 226 | program = self.PROGRAMS[name].format(python=sys.executable) |
206 | 227 |
|
207 | 228 | try: |
208 | | - proc = subprocess.Popen( |
| 229 | + proc = create_process_group( |
209 | 230 | ["bpftrace", "-e", program, "-c", " ".join(subcommand)], |
210 | 231 | stdout=subprocess.PIPE, |
211 | 232 | stderr=subprocess.PIPE, |
212 | 233 | universal_newlines=True, |
213 | 234 | ) |
214 | 235 | stdout, stderr = proc.communicate(timeout=60) |
215 | 236 | except subprocess.TimeoutExpired: |
216 | | - proc.kill() |
| 237 | + kill_process_group(proc) |
217 | 238 | raise AssertionError("bpftrace timed out") |
218 | 239 | except (FileNotFoundError, PermissionError) as e: |
219 | 240 | raise unittest.SkipTest(f"bpftrace not available: {e}") |
@@ -243,15 +264,15 @@ def assert_usable(self): |
243 | 264 | # Check if bpftrace is available and can attach to USDT probes |
244 | 265 | program = f'usdt:{sys.executable}:python:function__entry {{ printf("probe: success\\n"); exit(); }}' |
245 | 266 | try: |
246 | | - proc = subprocess.Popen( |
| 267 | + proc = create_process_group( |
247 | 268 | ["bpftrace", "-e", program, "-c", f"{sys.executable} -c pass"], |
248 | 269 | stdout=subprocess.PIPE, |
249 | 270 | stderr=subprocess.PIPE, |
250 | 271 | universal_newlines=True, |
251 | 272 | ) |
252 | 273 | stdout, stderr = proc.communicate(timeout=10) |
253 | 274 | except subprocess.TimeoutExpired: |
254 | | - proc.kill() |
| 275 | + kill_process_group(proc) |
255 | 276 | proc.communicate() # Clean up |
256 | 277 | raise unittest.SkipTest("bpftrace timed out during usability check") |
257 | 278 | except OSError as e: |
|
0 commit comments