From d70f0029f0808e0a3724150a081015e0f943dfb5 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 14:59:17 -0300 Subject: A command pane's command is over when its process exits, not when its pty closes A job left in the background (sleep 100 &) held the pty open, so the pane stayed running and the child a zombie until the job ended; a command that closed its terminal and ran on got its end of file at once, the host waited 100 ms for an exit, reported exit ? and hung it up. Now each command's child is watched on a thread (waitid with WNOWAIT, so its pid stays its own until the host reaps it), and the host tells the core the exit from that: after the pty's end of file, so the output before the exit is in, or 50 ms after the exit without one, a job holding the pty. The pty stays open until both, so a command that let go of its terminal is never hung up by it. All four front ends; a host that cannot start the watcher reads the exit at end of file as before. Tests: host_io's for both cases, and cmdexit.snap end to end. Co-Authored-By: Claude Opus 5.5 --- src/detached/wire.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/detached/wire.zig') diff --git a/src/detached/wire.zig b/src/detached/wire.zig index 94bd7f0b..0854ce3e 100644 --- a/src/detached/wire.zig +++ b/src/detached/wire.zig @@ -819,7 +819,7 @@ fn clientTag(msg: ClientMsg) ClientTag { return switch (msg) { .event => |ev| switch (ev) { // Machine-local reports and 9P requests belong to the session owner. - .output, .eof, .lsp_resp, .pipe_resp, .file_changed, .tick => unreachable, + .output, .eof, .exited, .lsp_resp, .pipe_resp, .file_changed, .tick => unreachable, inline else => |_, t| @field(ClientTag, @tagName(t)), }, inline else => |_, t| @field(ClientTag, @tagName(t)), @@ -946,7 +946,7 @@ pub fn encodeClient(out: []u8, msg: ClientMsg) Error![]const u8 { .touch_scroll => |v| try w.putF32(v), .pointer_leave => {}, // See `clientTag`: no tag, so nothing to encode. - .output, .eof, .lsp_resp, .pipe_resp, .file_changed, .tick => unreachable, + .output, .eof, .exited, .lsp_resp, .pipe_resp, .file_changed, .tick => unreachable, }, } try finishMessage(&w, at); @@ -1076,7 +1076,7 @@ pub fn clientBound(msg: ClientMsg) usize { .paste => |b| b.len, .command => |line| line.len, // See `clientTag`: not on this wire in this direction. - .output, .eof, .lsp_resp, .pipe_resp, .file_changed, .tick => unreachable, + .output, .eof, .exited, .lsp_resp, .pipe_resp, .file_changed, .tick => unreachable, }, }; } -- cgit v1.3