diff options
Diffstat (limited to 'src/ninep/tree.zig')
| -rw-r--r-- | src/ninep/tree.zig | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/src/ninep/tree.zig b/src/ninep/tree.zig index f98429ab..a85a1873 100644 --- a/src/ninep/tree.zig +++ b/src/ninep/tree.zig @@ -61,6 +61,20 @@ pub fn failText(tag: u64, errno: u16, text: []const u8) Reply { pub const e_bad_addr = "bad address syntax"; pub const e_bad_ctl = "ill-formed control message"; 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"; + +/// Handles that mark an open as the one reading `event` or `pty/data`, so the +/// release knows to give the file up; other opens get `open_handle`. +const open_handle: u32 = 1; +// ponytail: EBUSY spelled locally; use E.BUSY once cloud9 names it and pardes bumps the pin. +const e_busy: u16 = 16; +const reader_handle: u32 = 2; + +fn reads(omode: u8) bool { + return omode & 3 != 1; // OWRITE is the one access mode that never reads +} /// 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 @@ -167,7 +181,7 @@ pub const PaneFile = enum(u5) { pub fn mode(f: PaneFile) u16 { return switch (f) { .dir, .pty => 0o755, - .errors, .pty_ctl => 0o222, + .errors => 0o222, .pty_status => 0o444, else => 0o666, }; @@ -507,16 +521,26 @@ fn open(p: *Pardes, req: Req, target: Target) Reply { if (t.file.inPty() and !pn.isTerminal()) return Reply.fail(req.tag, E.NOENT); switch (t.file) { .body => if (pn.isTerminal()) return screen.openSnapshot(p, req, false), + // Reads of these consume, so two readers would each see half + // the stream; the second is refused rather than robbed. .event => { + const reader = reads(req.omode); + if (reader and pf.event_reader) return failText(req.tag, e_busy, e_in_use); pf.readers +|= 1; p.fs.listeners +|= 1; + pf.event_reader = pf.event_reader or reader; + if (reader) return .{ .tag = req.tag, .handle = reader_handle }; + }, + .pty_data => if (reads(req.omode)) { + if (pf.pty_readers > 0) return failText(req.tag, e_busy, e_in_use); + pf.pty_readers = 1; + return .{ .tag = req.tag, .handle = reader_handle }; }, - .pty_data => pf.pty_readers +|= 1, else => {}, } }, } - return .{ .tag = req.tag, .handle = 1 }; + return .{ .tag = req.tag, .handle = open_handle }; } /// Tremove closes a pane. Nothing else in the tree can be removed, and this @@ -549,12 +573,13 @@ fn releaseHandle(p: *Pardes, req: Req) Reply { const id = p.paneBySerial(t.serial) orelse return .{ .tag = req.tag }; const pf = &p.fs.panes[id]; if (t.file == .pty_data) { - if (pf.pty_readers == 0) return .{ .tag = req.tag }; + if (req.handle != reader_handle or pf.pty_readers == 0) return .{ .tag = req.tag }; pf.pty_readers -= 1; if (pf.pty_readers == 0) pf.pty_out.clearAndFree(p.gpa); return .{ .tag = req.tag }; } if (pf.readers == 0) return .{ .tag = req.tag }; + if (req.handle == reader_handle) pf.event_reader = false; pf.readers -= 1; p.fs.listeners -|= 1; if (pf.readers == 0) pf.tag_snap.clearAndFree(p.gpa); |
