From 7dc3891ed574d6e96548f592b09b0f8abc87ae2a Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sun, 27 Sep 2026 20:20:27 -0300 Subject: Keep what each open holds in one table of open records Snapshots (and /log's cursor), runs, and the reader_handle constants for event and pty/data each reused the open handle and each validated handle and node on its own. Now p.fs.opens is one table of 64 records, each the node it was opened on and a tagged union of what it holds, like lib9p's per-fid aux and acme's Fid (editors/acme/dat.h:373-385): one lookup (openOf), one release, ENFILE when full. A held read lives in its open's record, so it goes with the release. Opens that hold nothing answer handle 0 and take no record. Co-Authored-By: Claude Opus 5.5 --- src/fs.zig | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'src/fs.zig') diff --git a/src/fs.zig b/src/fs.zig index c2e88b10..4f395b1c 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -321,7 +321,7 @@ test "virtual writes enforce permissions even when contents are empty" { try std.testing.expectError(error.IsDirectory, write(p, "/virtual/src", bytes)); } else try std.testing.expectError(error.FileNotFound, write(p, "/virtual/src/fs.zig", bytes)); } - for (p.fs.snapshots) |snapshot| try std.testing.expect(snapshot.node == 0); + for (p.fs.opens) |o| try std.testing.expect(o.node == 0); } test "direct self reads and writes use the same dot paths as Look" { @@ -480,10 +480,7 @@ test "bounded reads release terminal snapshots after success and size refusal" { defer gpa.free(bytes); try std.testing.expectEqualStrings(expected, bytes); try std.testing.expectError(error.FileTooLarge, readLimit(p, path, expected.len - 1)); - for (p.fs.snapshots) |snapshot| { - try std.testing.expectEqual(@as(u64, 0), snapshot.node); - try std.testing.expect(snapshot.bytes == null); - } + for (p.fs.opens) |o| try std.testing.expectEqual(@as(u64, 0), o.node); } test "bounded reads probe size-unknown proc files at the exact limit" { @@ -1237,14 +1234,11 @@ pub const Namespace = struct { mounts: std.ArrayList(Mount) = .empty, node_name: [16]u8 = undefined, os_paths: std.ArrayList(OsPath) = .empty, - snapshots: [tree.screen.snapshot_slots]tree.screen.Snapshot = @splat(.{}), - runs: [tree.pty.run_slots]tree.pty.Run = @splat(.{}), + /// What each open holds between its open and its release. + opens: [tree.open_slots]tree.Open = @splat(.{}), out: std.ArrayList(u8) = .empty, listeners: u16 = 0, origin: u8 = 'K', - /// Reads that found nothing yet, one per open that can wait: the log's - /// and a run's opens, and one event and one pty/data reader a pane. - held: [tree.screen.snapshot_slots + tree.pty.run_slots + 2 * MAX_PANES]?tree.Held = @splat(null), /// Something a held read may be waiting on changed since they were last /// answered: a record queued, a run answered, a pane gone. news: bool = false, @@ -1266,8 +1260,7 @@ pub const Namespace = struct { st.mounts.deinit(gpa); for (st.os_paths.items) |entry| gpa.free(entry.path); st.os_paths.deinit(gpa); - for (st.snapshots) |snapshot| if (snapshot.bytes) |bytes| gpa.free(bytes); - for (&st.runs) |*slot| slot.reset(gpa, 0); + for (&st.opens) |*o| o.deinit(gpa); st.log.deinit(gpa); st.out.deinit(gpa); } -- cgit v1.3