Fix #604: test_proc_stream 8a waits for child exit instead of spin-count#666
Conversation
…stead of spin-count proc_wait only waitpid()s the pid and leaves the parent's pipe fds open (src/builtins.c builtin_proc_wait), so waiting first and then writing pins the intended property: EPIPE from a dead child, not EBADF from a closed handle. The 100k spin loop only hoped the child had been scheduled; under load it hadn't, and the write returned 5. Co-Authored-By: Kimi K3 <noreply@kimi.com>
|
Verified and merging — this is the right fix: it removes the timing dependency entirely rather than widening the window. The load-bearing claim checks out. I read On the evidence: I confirmed the fixed test passes deterministically (8/8 under 5 pinned busy-loops here). I could not reproduce the flake on the unfixed version on this box — it passed 8/8 under the same load — but that is a scheduling difference, not a refutation: this machine happens to let The mutant test (wait → no-op, 10/10 fail) is the part I like most — it proves the One file, +6/-6, no src changes, deterministic. Thank you. If you find the project useful or enjoyed contributing, a star helps others discover it. |
Fixes #604 — case 8a's 100,000-iteration spin loop replaced with
proc_wait of h[0]before the write, so "proc_write to a dead child returns -1" is pinned deterministically instead of by wall-clock luck.Which branch of your sketch, and why
You flagged the
proc_waitclose-and-reap question as the decider.builtin_proc_wait(src/builtins.c:3548) is a barewaitpid(pid, &status, 0)EINTR loop — it never touches the handle's fds. So after the wait, the parent's write end is still open, the only reader is gone (parent'sin_pipe[0]closed at spawn, FD_CLOEXEC on all four pipe fds, no SIGCHLD reaper anywhere in src/), SIGPIPE is already ignored, and the write hits EPIPE with 0 bytes written → -1. That's still the "write to dead child" property — not "closed handle" — so the plainproc_waitroute works and no try-wait polling is needed. The trailingproc_waitat the end of case 8 is dropped since the child is now reaped earlier (keeping it would be a discarded-return double-wait via ECHILD).One file, +6/-6;
want=-1untouched; no src/ changes.Evidence the fix is load-bearing (this box: 5 cores, all pinned with busy-loops)
MISMATCH 8a: got=5 want=-1proc_waitline is the synchronizationSo the flake reproduces reliably under load on this box and the fix eliminates it — same failure your macOS ARM leg hit on #643.
Full suite: 3085/3085 before and after (release build, umask 022).
Generated by Claude Fable 5 (brief, review), Kimi K3 (implementation)