From 90f5c414a90afec978c8c0add58fd2a7e29acbaa Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 29 Sep 2026 02:21:57 -0300 Subject: A read on a closed pane's event ends ENOENT, and the pane cap is ENOSPC 9ns reads an error's words, not its errno: "window shut down" came out as EIO where every other file of a gone pane gives ENOENT, and "no pane slots" as EIO. The event and pty/data reads a pane closed under now say "no such pane: its window shut" (ENOENT), and the cap says "no space for a pane: 64 max" (ENOSPC; 9ns has no word for ENFILE). Co-Authored-By: Claude Opus 5.5 --- src/ninep/tree.zig | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/ninep/tree.zig') diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index 278732b5..aec3cab7 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -66,7 +66,10 @@ pub const e_bad_event = "bad event syntax"; /// A second open reading a file whose reads consume: rio's word for it /// (windows/rio/xfid.c:25), which 9ns turns into EBUSY. pub const e_in_use = "file in use"; -pub const e_shut_down = "window shut down"; +/// A read held on a pane's event or pty/data that the pane closed under. +/// acme says "window shut down" (xfid.c:1005), which 9ns reads as EIO; +/// these words read as ENOENT, what every other file of a gone pane gives. +pub const e_shut_down = "no such pane: its window shut"; /// Tremove closes a pane; nothing else in the tree is created or destroyed by /// the protocol, and wstat stays a truncation. Making a pane is an open of @@ -709,7 +712,7 @@ fn open(p: *Pardes, req: Req, target: Target) Reply { // pane it made, so reading it twice answers the same one and // closing it leaves the pane alone. .new => { - const slot = p.freeSlot() orelse return failText(req.tag, E.NFILE, std.fmt.bufPrint(&p.fs.ename, "pane/new: " ++ pardes.Messages.no_pane_slots, .{pardes.MAX_PANES}) catch "no pane slots"); + const slot = p.freeSlot() orelse return failText(req.tag, E.NOSPC, std.fmt.bufPrint(&p.fs.ename, "pane/new: " ++ pardes.Messages.no_pane_slots, .{pardes.MAX_PANES}) catch "no space for a pane"); p.newScratchFor(p.active, .fs); const made = p.panes[slot] orelse return Reply.fail(req.tag, E.NFILE); return .{ .tag = req.tag, .handle = made.serial }; @@ -939,7 +942,7 @@ fn readFile(p: *Pardes, req: Req, target: Target) Reply { // An event or pty/data read the pane closed under: acme's // answer to the same (editors/acme/xfid.c:1005). if (openOf(p, req)) |o| if (o.what == .event or o.what == .pty_data) - return failText(req.tag, E.IO, e_shut_down); + return failText(req.tag, E.NOENT, e_shut_down); return Reply.fail(req.tag, E.NOENT); }; const pn = p.panes[id].?; @@ -1427,9 +1430,9 @@ test "at the pane cap, pane/new, look and New each say so, and look reads back e const new = @intFromEnum(TopFile.new); while (p.freeSlot() != null) try testing.expectEqual(Status.ok, call(p, .{ .tag = 1, .op = .open, .node = new }).reply.status); var want: [64]u8 = undefined; - const said = try std.fmt.bufPrint(&want, "no pane slots: {d} max", .{pardes.MAX_PANES}); + const said = try std.fmt.bufPrint(&want, "no space for a pane: {d} max", .{pardes.MAX_PANES}); const refused = call(p, .{ .tag = 2, .op = .open, .node = new }); - try testing.expectEqual(E.NFILE, refused.errno()); + try testing.expectEqual(E.NOSPC, refused.errno()); try testing.expect(std.mem.endsWith(u8, refused.reply.ename, said)); try testing.expect(th.logHas(p, said)); // A look that would open a pane fails its write, and says the same. -- cgit v1.3