summaryrefslogtreecommitdiff
path: root/src/9p_io.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/9p_io.zig')
-rw-r--r--src/9p_io.zig28
1 files changed, 23 insertions, 5 deletions
diff --git a/src/9p_io.zig b/src/9p_io.zig
index 9a38b438..57df0c5f 100644
--- a/src/9p_io.zig
+++ b/src/9p_io.zig
@@ -266,6 +266,7 @@ pub const Listener = struct {
const restores = pardes.turn.restores;
// Asked first: a release that runs a held line has none after.
const changes = pardes.ctlfs.changesPane(core, req);
+ const fills = pardes.ctlfs.holdsPage(core, req);
const reply = core.serveFs(req);
if (req.op == .release and quiet) l.collectOs();
// A read with nothing yet stays parked in the engine, and the core
@@ -299,6 +300,13 @@ pub const Listener = struct {
// file written. A change carries no payload, so the reply is still
// whole after the wait.
l.kick();
+ // A read that put a /pager open's text in (ctl.fillPager), or a
+ // close that handed it to the editor's step, waits on nothing the
+ // editor performs: its answer goes now, while the turn still keeps
+ // a read's payload whole. Waiting would hang a close through a
+ // mount: 9ns answers nothing else on it while a clunk is out, and
+ // the editor's step may be out opening a file through that mount.
+ if (fills) return conn.reply(&reply, core.fsPayload(reply));
// A refusal answers at once: its text may be in the core's one
// buffer for it, which a request run while this one waited would
// write over.
@@ -2341,10 +2349,12 @@ pub const Client = struct {
gpa.destroy(s);
}
- /// Writes `request` to `path` and reads the answer on the same open,
- /// as /pane/new answers its own open: a session's last answer, from
- /// another client, can never be what comes back. `exec 3<>file`.
- pub fn ask(gpa: std.mem.Allocator, dial: []const u8, path: []const u8, request: []const u8) ![]u8 {
+ /// Writes `request`, then `more`, to `path` and reads the answer on the
+ /// same open, as /pane/new answers its own open: a session's last
+ /// answer, from another client, can never be what comes back. `exec
+ /// 3<>file`. `more` (`pardes -`'s text after its /pager line) goes in
+ /// Twrites at rising offsets, each answer giving the next its budget.
+ pub fn ask(gpa: std.mem.Allocator, dial: []const u8, path: []const u8, request: []const u8, more: []const u8) ![]u8 {
if (comptime !supported) return error.Unsupported;
var names: [max_depth][]const u8 = undefined;
const n = try elements(path, &names);
@@ -2356,7 +2366,15 @@ pub const Client = struct {
defer endSession(gpa, s);
const fid = (try walkTo(s, names[0..n], &remote)).fid;
_ = try s.ask(.{ .open = .{ .fid = fid, .mode = ninep.ordwr } }, &remote);
- _ = try s.ask(.{ .write = .{ .fid = fid, .offset = 0, .data = request } }, &remote);
+ var written: usize = 0;
+ while (written < request.len + more.len) {
+ const from = if (written < request.len) request[written..] else more[written - request.len ..];
+ const chunk = from[0..@min(from.len, s.cl.maxWrite())];
+ const count = (try s.ask(.{ .write = .{ .fid = fid, .offset = written, .data = chunk } }, &remote)).write;
+ if (count == 0 or count > chunk.len) return Error.Botch;
+ written += count;
+ s.deadline = nowMs() +| write_budget_ms;
+ }
var out: std.ArrayList(u8) = .empty;
errdefer out.deinit(gpa);
while (true) {