diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-27 20:25:26 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 5d9a56d47a9cd5eefc4c8bf03709f2e96febb212 (patch) | |
| tree | 3471e580d122efbaa881b338ad3542d864c65f65 /src/ninep/tree.zig | |
| parent | 7dc3891ed574d6e96548f592b09b0f8abc87ae2a (diff) | |
| download | pardes-5d9a56d47a9cd5eefc4c8bf03709f2e96febb212.tar.gz pardes-5d9a56d47a9cd5eefc4c8bf03709f2e96febb212.zip | |
A pane's ctl takes acme's lock and unlock
A client doing an edit of several writes to addr and data had no way to
keep another client's from landing in between. acme's window ctl takes
lock and unlock for this (editors/acme/xfid.c:603-611): a qlock that
blocks a second locker, owned by the fid that wrote it and given up when
that fid is clunked, binding only clients that ask. pardes does the same:
the open's record holds it, a second lock parks until unlock, close or
the pane closing, and no other write is refused for it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/ninep/tree.zig')
| -rw-r--r-- | src/ninep/tree.zig | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index bc32ad33..c9e7b31a 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -122,6 +122,8 @@ pub const Open = struct { event: bool, /// The one open reading a pane's pty/data. pty_data, + /// An open that may write a pane's ctl, and so hold its lock. + ctl, } = .{ .snapshot = null }, /// A read that found nothing yet (`.again`), kept to be answered when /// this open's file has something, the way factotum keeps its log's @@ -141,7 +143,7 @@ pub const Open = struct { .snapshot => |bytes| if (bytes) |b| gpa.free(b), .log => |log| gpa.free(log.bytes), .run => |run| gpa.free(run.output), - .event, .pty_data => {}, + .event, .pty_data, .ctl => {}, } o.* = .{}; } @@ -577,6 +579,10 @@ fn open(p: *Pardes, req: Req, target: Target) Reply { .event => if (reader and pn.fs.event_reader) return failText(req.tag, E.BUSY, e_in_use) else .{ .event = reader }, .pty_data => if (!reader) return .{ .tag = req.tag } else if (pn.fs.pty_reader) return failText(req.tag, E.BUSY, e_in_use) else .pty_data, .pty_run => .{ .run = .{} }, + .ctl => switch (req.omode & 3) { + 1, 2 => .ctl, // OWRITE, ORDWR + else => return .{ .tag = req.tag }, + }, else => return .{ .tag = req.tag }, }; }, @@ -605,7 +611,7 @@ fn open(p: *Pardes, req: Req, target: Target) Reply { pn.fs.event_reader = pn.fs.event_reader or reader; }, .pty_data => pane_of.?.fs.pty_reader = true, - .run => {}, + .run, .ctl => {}, } return .{ .tag = req.tag, .handle = @intCast(i + 1) }; } @@ -652,6 +658,13 @@ fn releaseHandle(p: *Pardes, req: Req) void { .run => if (pn.fs.run == @as(u8, @intCast(req.handle - 1))) { pn.fs.run = null; }, + // Closing the open that holds the lock gives it up, as acme's clunk + // of its ctlfid does (editors/acme/xfid.c:211); a write parked on + // `lock` goes again. + .ctl => if (pn.fs.lock == @as(u8, @intCast(req.handle - 1))) { + pn.fs.lock = null; + pardes.turn.parked = true; + }, .snapshot, .log => {}, }; o.deinit(p.gpa); |
