summaryrefslogtreecommitdiff
path: root/src/detached
diff options
context:
space:
mode:
Diffstat (limited to 'src/detached')
-rw-r--r--src/detached/server.zig44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig
index a3694c57..0cf1729f 100644
--- a/src/detached/server.zig
+++ b/src/detached/server.zig
@@ -351,6 +351,7 @@ pub const Session = struct {
.pty_write = ptyWrite,
.pty_resize = ptyResize,
.pty_signal = ptySignal,
+ .close_pty = closePaneShell,
.tty_taken = ttyTaken,
.write_file = writeFile,
.write_dump = writeDump,
@@ -606,6 +607,11 @@ pub const Session = struct {
}
}
+ fn closePaneShell(ctx: ?*anyopaque, pane: u8) void {
+ const s = of(ctx);
+ if (pane < s.ptys.len) s.closePty(pane);
+ }
+
fn closePty(s: *Session, pane: u8) void {
const pt = &s.ptys[pane];
if (pt.fd < 0) return;
@@ -1229,6 +1235,44 @@ test "detached queued results preserve current requests and are discarded before
try std.testing.expect(s.core.lsp_wait == null);
}
+test "a detached session's terminal pane takes its shell with it when it closes" {
+ const gpa = std.testing.allocator;
+ var s: Session = .{
+ .gpa = gpa,
+ .worker_gpa = gpa,
+ .io = std.testing.io,
+ .core = try pardes.Pardes.init(gpa, .{ .tty_only = true, .cols = 40, .rows = 12 }),
+ .cols = 40,
+ .rows = 12,
+ };
+ defer s.core.deinit();
+ defer s.deinit();
+ // A stand-in shell: it waits for a signal, and a hangup ends it.
+ const pid = libc.fork();
+ if (pid == 0) while (true) {
+ _ = libc.poll(&[0]libc.pollfd{}, 0, -1);
+ };
+ try std.testing.expect(pid > 0);
+ var fds: [2]c_int = undefined;
+ try std.testing.expectEqual(@as(c_int, 0), libc.pipe(&fds));
+ defer _ = libc.close(fds[1]);
+ s.ptys[3] = .{ .fd = fds[0], .pid = pid };
+ const host = s.host();
+ host.vtable.close_pty.?(host.ctx, 3);
+ try std.testing.expect(s.ptys[3].fd < 0);
+ const deadline = monotonicMs() + 2000;
+ while (monotonicMs() < deadline) {
+ s.harvest();
+ const running = s.ptys[3].pid != 0 or for (s.retired_shells) |shell| {
+ if (shell.pid == pid) break true;
+ } else false;
+ if (!running) break;
+ _ = libc.poll(&[0]libc.pollfd{}, 0, 5);
+ }
+ try std.testing.expect(s.ptys[3].pid == 0);
+ for (s.retired_shells) |shell| try std.testing.expect(shell.pid != pid);
+}
+
test "detached worker setup failure completes requests without changing document bytes" {
const gpa = std.testing.allocator;
var failing = std.testing.FailingAllocator.init(gpa, .{ .fail_index = 0 });