diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/builtins.zig | 2 | ||||
| -rw-r--r-- | src/detached/server.zig | 3 | ||||
| -rw-r--r-- | src/gui/gui.zig | 3 | ||||
| -rw-r--r-- | src/macos.zig | 3 | ||||
| -rw-r--r-- | src/ninep/pty.zig | 2 | ||||
| -rw-r--r-- | src/pardes.zig | 23 | ||||
| -rw-r--r-- | src/tty/tty.zig | 4 |
7 files changed, 32 insertions, 8 deletions
diff --git a/src/builtins.zig b/src/builtins.zig index 4815a114..5273cf37 100644 --- a/src/builtins.zig +++ b/src/builtins.zig @@ -440,7 +440,7 @@ pub const Kill = struct { if (std.mem.eql(u8, w, first)) break; } else continue; } - c.p.emit(.{ .signal_pty = .{ .pane = @intCast(id), .sig = .term } }); + c.p.emit(.{ .signal_pty = .{ .pane = @intCast(id), .serial = pane.serial, .sig = .term } }); stopped = true; continue; }; diff --git a/src/detached/server.zig b/src/detached/server.zig index 202eafb3..5bf2384b 100644 --- a/src/detached/server.zig +++ b/src/detached/server.zig @@ -523,7 +523,8 @@ pub const Session = struct { const s = of(ctx); if (pane >= s.ptys.len) return; const pt = s.ptys[pane]; - if (pt.fd < 0) return; + // A command whose exit is recorded is reaped: its group may be another's. + if (pt.fd < 0 or pt.cmd.exited) return; host_io.signalTty(pt.pid, pt.fd, sig); } diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 175db9e2..46bd5ffc 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -4246,7 +4246,8 @@ fn ptyResize(ctx: ?*anyopaque, pane: u8, cols: u16, rows: u16) void { fn ptySignal(ctx: ?*anyopaque, pane: u8, sig: pardes.PtySignal) void { const s = shellOf(ctx); - if (s.ptys[pane]) |pt| if (pt.fd >= 0) host_io.signalTty(pt.pid, pt.fd, sig); + // A command whose exit is recorded is reaped: its group may be another's. + if (s.ptys[pane]) |pt| if (pt.fd >= 0 and !pt.cmd.exited) host_io.signalTty(pt.pid, pt.fd, sig); } fn ttyTaken(ctx: ?*anyopaque, pane: u8) bool { diff --git a/src/macos.zig b/src/macos.zig index 1327b064..d6ceb535 100644 --- a/src/macos.zig +++ b/src/macos.zig @@ -2481,7 +2481,8 @@ fn ptyResize(ctx: ?*anyopaque, pane: u8, cols: u16, rows: u16) void { fn ptySignal(ctx: ?*anyopaque, pane: u8, sig: pardes.PtySignal) void { const st = hostState(ctx); - if (st.ptys[pane]) |pt| host_io.signalTty(pt.pid, pt.file.handle, sig); + // A command whose exit is recorded is reaped: its group may be another's. + if (st.ptys[pane]) |pt| if (!pt.cmd.exited) host_io.signalTty(pt.pid, pt.file.handle, sig); } fn ttyTaken(ctx: ?*anyopaque, pane: u8) bool { diff --git a/src/ninep/pty.zig b/src/ninep/pty.zig index 6065dab2..88dafdfc 100644 --- a/src/ninep/pty.zig +++ b/src/ninep/pty.zig @@ -65,7 +65,7 @@ fn verb(p: *Pardes, id: usize, line: []const u8, apply: bool) bool { const which = signalNamed(words.next() orelse return false) orelse return false; if (words.next() != null) return false; if (!apply) return true; - p.emit(.{ .signal_pty = .{ .pane = @intCast(id), .sig = which } }); + p.emit(.{ .signal_pty = .{ .pane = @intCast(id), .serial = pane.serial, .sig = which } }); }, .exec => { if (words.next() != null) return false; diff --git a/src/pardes.zig b/src/pardes.zig index 1539637c..5ba95be3 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -1468,6 +1468,22 @@ test "a command pane shows how its command ended, and the next command there run var want: [64]u8 = undefined; try std.testing.expect(std.mem.indexOf(u8, log.bytes, try std.fmt.bufPrint(&want, "run {d} make\n", .{pane.serial})) != null); try std.testing.expect(std.mem.indexOf(u8, log.bytes, try std.fmt.bufPrint(&want, "exit {d} 2\n", .{pane.serial})) != null); + // A signal for a pane is not performed on whoever takes its slot. + const Count = struct { + var signals: usize = 0; + const vtable: Host.VTable = .{ .pty_signal = signal }; + fn signal(_: ?*anyopaque, _: u8, _: PtySignal) void { + signals += 1; + } + }; + const host_before = p.host; + p.host = .{ .vtable = &Count.vtable }; + try std.testing.expect(p.executeBuiltinLine(0, "Kill make")); + try p.removePane(dst, null); + _ = try p.newCommand(dst, "", "other"); + while (p.nextEffect()) |effect| if (effect == .signal_pty) p.perform(effect); + try std.testing.expectEqual(@as(usize, 0), Count.signals); + p.host = host_before; // A command line longer than a command pane takes is refused. const long = "x" ** (exec.command_max + 1); try std.testing.expectEqual(@as(?usize, null), exec.execute(p, 1, long)); @@ -3187,7 +3203,8 @@ pub const Effect = union(enum) { spawn: struct { pane: u8, serial: u32, cwd: Buf(effect_path_cap) }, write: struct { pane: u8, bytes: Buf(64) }, resize_pty: struct { pane: u8, cols: u16, rows: u16 }, - signal_pty: struct { pane: u8, sig: PtySignal }, + /// For the pane whose serial is `serial`, as `spawn` is (perform). + signal_pty: struct { pane: u8, serial: u32, sig: PtySignal }, /// The terminal pane in this slot is gone: the shell hangs up its pty /// and ends the shell, rather than leave it running with nobody to read. close_pty: struct { pane: u8 }, @@ -4665,7 +4682,9 @@ pub const Pardes = struct { // screen, and the bytes are dropped rather than transcribed. .write => |w| if (v.pty_write) |f| f(p.host.ctx, w.pane, w.bytes.slice()), .resize_pty => |r| if (v.pty_resize) |f| f(p.host.ctx, r.pane, r.cols, r.rows), - .signal_pty => |s| if (v.pty_signal) |f| f(p.host.ctx, s.pane, s.sig), + // A signal for a pane that closed, its slot retaken in the same + // step, would reach another pane's child. + .signal_pty => |s| if (if (p.panes[s.pane]) |pane| pane.serial != s.serial else true) {} else if (v.pty_signal) |f| f(p.host.ctx, s.pane, s.sig), .close_pty => |c| if (v.close_pty) |f| f(p.host.ctx, c.pane), .open_link => |u| if (v.open_link) |f| f(p.host.ctx, u.slice()) diff --git a/src/tty/tty.zig b/src/tty/tty.zig index 8e3809b0..14417cd0 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -1250,7 +1250,9 @@ const Shell = struct { fn ptySignal(ctx: ?*anyopaque, pane: u8, sig: pardes.PtySignal) void { const s = of(ctx); - if (s.ptys[pane]) |pt| host_io.signalTty(pt.pid, pt.file.handle, sig); + // A command whose exit is recorded is reaped: its group may be + // another's by now. + if (s.ptys[pane]) |pt| if (!pt.cmd.exited) host_io.signalTty(pt.pid, pt.file.handle, sig); } /// The pane is gone: hang its pty up, which the kernel passes on to the |
