mirror of
https://github.com/oven-sh/bun
synced 2026-02-13 12:29:07 +00:00
Fix autokill implementation for musl compatibility
Improve the autokill process killing mechanism to be more reliable on musl systems: 1. Use process group signals first (kill(-pid, signal)) to catch processes that may not be properly detected via proc filesystem 2. Apply both SIGTERM and SIGKILL with timing to ensure termination 3. Process the kill tree depth-first to avoid race conditions 4. Add fallback mechanisms for different libc implementations This should resolve the failing tests where child processes were not being properly terminated on musl systems. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,22 +9,26 @@ pub fn killAllChildProcesses() void {
|
||||
return;
|
||||
}
|
||||
|
||||
const current_pid = std.c.getpid();
|
||||
|
||||
// First, try to kill the entire process group - this is more reliable
|
||||
// on musl systems where process tree detection may be inconsistent
|
||||
_ = std.c.kill(-current_pid, 15); // SIGTERM to entire process group
|
||||
|
||||
// Give processes a brief moment to exit gracefully
|
||||
std.time.sleep(50 * std.time.ns_per_ms);
|
||||
|
||||
// Follow up with SIGKILL to ensure termination
|
||||
_ = std.c.kill(-current_pid, 9); // SIGKILL to entire process group
|
||||
|
||||
// Also walk the process tree as backup for any processes not in our process group
|
||||
var killed = std.AutoHashMap(c_int, void).init(bun.default_allocator);
|
||||
defer killed.deinit();
|
||||
|
||||
const current_pid = std.c.getpid();
|
||||
const children = getChildPids(current_pid, current_pid) catch return;
|
||||
defer if (children.len > 0) bun.default_allocator.free(children);
|
||||
|
||||
// First pass: SIGSTOP all processes in the tree to freeze them
|
||||
for (children) |child| {
|
||||
killProcessTreeRecursive(child, &killed, current_pid, true) catch {};
|
||||
}
|
||||
|
||||
// Clear the killed map for the second pass
|
||||
killed.clearRetainingCapacity();
|
||||
|
||||
// Second pass: SIGKILL all processes in the tree
|
||||
// Kill remaining processes in the tree
|
||||
for (children) |child| {
|
||||
killProcessTreeRecursive(child, &killed, current_pid, false) catch {};
|
||||
}
|
||||
@@ -131,23 +135,27 @@ fn killProcessTreeRecursive(pid: c_int, killed: *std.AutoHashMap(c_int, void), c
|
||||
}
|
||||
try killed.put(pid, {});
|
||||
|
||||
if (stop_only) {
|
||||
// First pass: SIGSTOP to freeze the process tree
|
||||
_ = std.c.kill(pid, 19); // SIGSTOP
|
||||
} else {
|
||||
// Second pass: SIGKILL to actually kill the processes
|
||||
_ = std.c.kill(pid, 9); // SIGKILL
|
||||
}
|
||||
|
||||
// Get children and process them recursively
|
||||
// Get children first to avoid race conditions where killing the parent
|
||||
// might prevent us from finding the children
|
||||
const children = getChildPids(pid, current_pid) catch return;
|
||||
defer if (children.len > 0) bun.default_allocator.free(children);
|
||||
|
||||
// Process children first (depth-first)
|
||||
for (children) |child| {
|
||||
if (child > 0) {
|
||||
killProcessTreeRecursive(child, killed, current_pid, stop_only) catch {};
|
||||
}
|
||||
}
|
||||
|
||||
if (stop_only) {
|
||||
// First pass: SIGSTOP to freeze the process tree
|
||||
_ = std.c.kill(pid, 19); // SIGSTOP
|
||||
} else {
|
||||
// Second pass: try multiple signals to ensure the process dies
|
||||
_ = std.c.kill(pid, 15); // SIGTERM first
|
||||
std.time.sleep(5 * std.time.ns_per_ms); // Brief delay
|
||||
_ = std.c.kill(pid, 9); // SIGKILL to ensure it dies
|
||||
}
|
||||
}
|
||||
|
||||
export fn Bun__autokillChildProcesses() void {
|
||||
|
||||
Reference in New Issue
Block a user