Every liveness decision in the harness reads EOF off the master: the
"child is gone" refusals in send, resize and the mouse path, and the
fast Error::Eof every wait returns instead of burning its timeout. On
Unix that is the right signal — every slave descriptor closed is exactly
"no one can read this", and a reaped child says nothing about a
grandchild still holding the terminal. On Windows it never arrives: a
pseudoconsole's output pipe stays open until the console itself is
closed, whoever has exited. Five tests failed there the same way, with
the child gone and the harness insisting someone was listening (#149).
So where EOF cannot come, the reaped child is the signal. Each wait
loop now ticks an ExitWatch alongside its poll: once try_wait reports
the child gone and DRAIN_GRACE has passed with the terminal still open,
the state is marked at EOF and the wait returns what it would have on
Unix. wait_exit does the same after its drain grace expires. Both are
gated on cfg!(windows) through one named constant, so Unix behaviour is
byte-for-byte what it was; the whole suite there says so.
Refs #149
Signed-off-by: Vyncint Ng <115854244+vyncint@users.noreply.github.com>
Refs #149 — the first item of step 4, found by running the migrated suite (#276) on
windows-latest.The bug
Every liveness decision reads EOF off the master:
ensure_deliverable(the "child is gone" refusals insend,resize, and the mouse path) and the fastError::Eofevery wait returns instead of burning its timeout. On Unix that is the right signal, for the reason the code already states — EOF means every slave descriptor is closed, while a reaped child says nothing about a grandchild still reading. On Windows it never arrives: a pseudoconsole's output pipe stays open until the console itself is closed, whoever has exited. Five tests fail there identically, with the child gone and the harness insisting someone is listening:a_departed_child_is_refused_identically_on_every_platform·typed_input_to_a_departed_child_is_a_typed_error·a_mouse_click_at_a_departed_child_blames_the_child·resize_after_the_child_exits_is_refused_like_send·waits_fail_fast_on_eof_instead_of_burning_the_timeoutThe fix
Where EOF cannot come, the reaped child is the signal — one named constant,
EXIT_CLOSES_THE_TERMINAL = cfg!(windows), with the reasoning on it.ExitWatch::tickruns inside each wait loop's poll (wait_until,wait_frame,wait_idle,wait_stable): a non-blockingtry_wait; once the child is reaped andDRAIN_GRACEhas passed with the terminal still open,state.eof = trueand the wait returns exactly what it would have on Unix.wait_exitalready drained forDRAIN_GRACEwaiting on EOF; when that expires on Windows it now marks the terminal closed, so the refusals that follow await_exitfire.Verification
Unix: full suite, three feature configurations, both clippy targets. Windows:
windows.ymldispatched against this branch — the five tests above are the acceptance; result in a comment below.