diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-28 12:01:34 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 990c2e1b184e9cb1fddd8eb1b05a472cfb113dde (patch) | |
| tree | 0d3327598ff2522900c33e4018ca187a89fdbeb2 /src/tty/tty.zig | |
| parent | 78c60342022bc44307ad789aaef163ab96ebd08b (diff) | |
| download | pardes-990c2e1b184e9cb1fddd8eb1b05a472cfb113dde.tar.gz pardes-990c2e1b184e9cb1fddd8eb1b05a472cfb113dde.zip | |
A closed terminal's shell is reaped on tty and macOS, killed if it ignores the hangup
tty and macOS hung the pty up and called waitpid once without waiting, so a shell
still exiting, or one that ignores SIGHUP, stayed a zombie or ran on with nobody
reading it; tty also never reaped a shell that exited by itself, and its spawn
into an occupied slot closed the old pty without ending the shell. host_io's
retireShell says hangup, waits 100 ms on a thread (macOS has no host timer to
poll from), then kills and reaps. The gui's own retired list, when full, left the
slot holding the old shell and refused the next spawn into that pane; it now
hands that shell to retireShell instead.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/tty/tty.zig')
| -rw-r--r-- | src/tty/tty.zig | 14 |
1 files changed, 5 insertions, 9 deletions
diff --git a/src/tty/tty.zig b/src/tty/tty.zig index b2768ed6..128a7ead 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -1007,6 +1007,7 @@ const Shell = struct { if (s.ptys[e.id]) |*pt| { pt.reader.await(s.io) catch {}; // reader just finished; join it or its future leaks _ = libc.close(pt.file.handle); + host_io.retireShell(pt.pid); s.ptys[e.id] = null; } core.update(.{ .eof = .{ .pane = @intCast(e.id) } }); @@ -1193,11 +1194,7 @@ const Shell = struct { fn spawn(ctx: ?*anyopaque, pane: u8, cwd: []const u8) void { const s = of(ctx); - if (s.ptys[pane]) |*old| { - old.reader.cancel(s.io) catch {}; - _ = libc.close(old.file.handle); - s.ptys[pane] = null; - } + closePty(ctx, pane); // a shell still in the slot goes first, reaped s.gens[pane] +%= 1; const child = host_io.forkShell(s.core, pane, s.prompt_rcs, s.core.shellBin(), cwd, s.core.screen_h, s.core.screen_w, s.fs) catch |err| return s.core.reportError(pane, "shell", err); s.ptys[pane] = .{ .file = child.file, .pid = child.pid, .reader = .{ .any_future = null, .result = {} } }; @@ -1229,8 +1226,8 @@ const Shell = struct { } /// The pane is gone: hang its pty up, which the kernel passes on to the - /// shell as SIGHUP, and say it too for a shell that ignores the tty's. - /// Output still in flight carries the old generation and is dropped. + /// shell as SIGHUP, and retire the shell. Output still in flight + /// carries the old generation and is dropped. fn closePty(ctx: ?*anyopaque, pane: u8) void { const s = of(ctx); var pt = s.ptys[pane] orelse return; @@ -1238,8 +1235,7 @@ const Shell = struct { s.gens[pane] +%= 1; pt.reader.cancel(s.io) catch {}; _ = libc.close(pt.file.handle); - _ = libc.kill(pt.pid, posix.SIG.HUP); - _ = libc.waitpid(pt.pid, null, posix.W.NOHANG); + host_io.retireShell(pt.pid); } fn ttyTaken(ctx: ?*anyopaque, pane: u8) bool { |
