|
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,24 @@ 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 | + if USE_PROCESS_GROUP: |
| 63 | + try: |
| 64 | + os.killpg(proc.pid, signal.SIGKILL) |
| 65 | + except ProcessLookupError: |
| 66 | + pass |
| 67 | + else: |
| 68 | + proc.kill() |
| 69 | + proc.communicate() # Clean up |
| 70 | + |
| 71 | + |
53 | 72 | class TraceBackend: |
54 | 73 | EXTENSION = None |
55 | 74 | COMMAND = None |
@@ -205,15 +224,15 @@ def run_case(self, name, optimize_python=None): |
205 | 224 | program = self.PROGRAMS[name].format(python=sys.executable) |
206 | 225 |
|
207 | 226 | try: |
208 | | - proc = subprocess.Popen( |
| 227 | + proc = create_process_group( |
209 | 228 | ["bpftrace", "-e", program, "-c", " ".join(subcommand)], |
210 | 229 | stdout=subprocess.PIPE, |
211 | 230 | stderr=subprocess.PIPE, |
212 | 231 | universal_newlines=True, |
213 | 232 | ) |
214 | 233 | stdout, stderr = proc.communicate(timeout=60) |
215 | 234 | except subprocess.TimeoutExpired: |
216 | | - proc.kill() |
| 235 | + kill_process_group(proc) |
217 | 236 | raise AssertionError("bpftrace timed out") |
218 | 237 | except (FileNotFoundError, PermissionError) as e: |
219 | 238 | raise unittest.SkipTest(f"bpftrace not available: {e}") |
@@ -243,16 +262,15 @@ def assert_usable(self): |
243 | 262 | # Check if bpftrace is available and can attach to USDT probes |
244 | 263 | program = f'usdt:{sys.executable}:python:function__entry {{ printf("probe: success\\n"); exit(); }}' |
245 | 264 | try: |
246 | | - proc = subprocess.Popen( |
| 265 | + proc = create_process_group( |
247 | 266 | ["bpftrace", "-e", program, "-c", f"{sys.executable} -c pass"], |
248 | 267 | stdout=subprocess.PIPE, |
249 | 268 | stderr=subprocess.PIPE, |
250 | 269 | universal_newlines=True, |
251 | 270 | ) |
252 | 271 | stdout, stderr = proc.communicate(timeout=10) |
253 | 272 | except subprocess.TimeoutExpired: |
254 | | - proc.kill() |
255 | | - proc.communicate() # Clean up |
| 273 | + kill_process_group(proc) |
256 | 274 | raise unittest.SkipTest("bpftrace timed out during usability check") |
257 | 275 | except OSError as e: |
258 | 276 | raise unittest.SkipTest(f"bpftrace not available: {e}") |
|
0 commit comments