fix(runtime): close a child's output pipes before its input #271
Loading…
Reference in a new issue
No description provided.
Delete branch "loop/270-io-child-close-race"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes the red tier B on main (
test_io_closing_a_child_ends_a_read_that_waitsanswered 0 instead of-EBADF, run 645).Cause
A runtime race, not a test flake.
torb_child_done(runtime/stream.c) closed the child's pipes in the order input, output, errors. Closing the input pipe ofcatlets it see the end of its input, exit and close its stderr; epoll then reports the error pipe readable (hang-up), the IO thread'sread()gets 0 and completes the parked read with end of file, beforetorb_io_pipe_close(errors_polled)had marked that pipe closed.torb_io_completeonly maps negative results of a closed pipe toCLOSED, so the 0 stood. Whether the child won the race depended on scheduling on the runner, which is why the PR head was green and main red.The documented semantics (stream.c header, STREAMS.md section 14) say closing the child ends a read that waits with
EBADF, so the runtime is fixed, not the test.Fix
torb_child_donecloses the pipes the child writes (output, errors) before the one it reads (input). Each pipe'sclosedflag is set under its lock before the child can see the end of its input, so a waiting read always completes withCLOSED->EBADF. A child that ends on its own before the close still yields a legitimate end of file.Relation to #218
#218 (
test_io_a_cancelled_wait_releases_its_registration, a socket receive leaking its poller registration after cancel) is a different path (no child, no close ordering) and stays out of scope.Closes #270
Approved.
closedflag is set before the child can see EOF, so a parked read completes with CLOSED/EBADF. The reordering keeps the pairing of platform close then io close per pipe, and a child that ends on its own still yields a legitimate EOF.torb_child_doneplus the test; #218 is correctly left out.Non-blocking: none.
std/cipherwith ChaCha20-Poly1305 (RFC 8439) #264