a73x

fc24fa27

test: the reparented sleeper does not hold the pipe naming it

a73x   2026-09-03 19:13

Commit message
test: the reparented sleeper does not hold the pipe naming it

waitPidGone's grandchild inherited the pipe the test reads its pid
through, so the read blocked for the sleeper's whole lifetime and the
aliveness check that opens the test raced its death. macOS lost that race
outright. The sleeper's stdio goes to /dev/null now and it lives a second,
so the shell exits at once and the wait has something to wait for.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SakwJEwD9dXBoRP5kWbemW

src/cli/main.zig
Old New
@@ -2020,7 +2020,15 @@ test "waitPidGone: returns only once the OS has no such process" {
2020 // Use a grandchild because a direct child can remain as a zombie that signal 2020 // Use a grandchild because a direct child can remain as a zombie that signal
2021 // zero still finds. The shell exits after printing the sleeper pid, leaving 2021 // zero still finds. The shell exits after printing the sleeper pid, leaving
2022 // the reparented process to terminate independently. 2022 // the reparented process to terminate independently.
2023 var child = std.process.Child.init(&.{ "sh", "-c", "sleep 0.3 & echo $!" }, std.testing.allocator); 2023 //
2024 // The sleeper's stdio goes to /dev/null so it does not hold the pipe this
2025 // test reads the pid through. Inheriting it made the read below block for
2026 // the sleeper's whole lifetime, so the pid was already dying by the time
2027 // the aliveness check ran and the wait proved nothing — on macOS the check
2028 // lost that race outright and the test failed at its first line. A second
2029 // of life, spent while `waitPidGone` polls, is what makes the wait mean
2030 // something.
2031 var child = std.process.Child.init(&.{ "sh", "-c", "sleep 1 >/dev/null 2>&1 </dev/null & echo $!" }, std.testing.allocator);
2024 child.stdout_behavior = .Pipe; 2032 child.stdout_behavior = .Pipe;
2025 try child.spawn(); 2033 try child.spawn();
2026 var buf: [32]u8 = undefined; 2034 var buf: [32]u8 = undefined;