diff options
Diffstat (limited to 'src/acmefs.zig')
| -rw-r--r-- | src/acmefs.zig | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/src/acmefs.zig b/src/acmefs.zig index 21beb7f6..dc2780fe 100644 --- a/src/acmefs.zig +++ b/src/acmefs.zig @@ -690,7 +690,28 @@ pub fn notePtyOutput(p: *Pardes, id: usize, bytes: []const u8) void { if (id >= MAX_PANES or bytes.len == 0) return; const pf = &p.fs.panes[id]; if (pf.pty_readers == 0) return; - pf.pty_out.push(p.gpa, bytes); + // SPLIT, because a record larger than `queue_cap - 4` can never be + // admitted: `Queue.push`'s eviction loop pops until `peek()` is null — + // destroying every unread byte the script was still owed — and then drops + // the new record too, silently. + // + // That is not a theoretical size. Every host reads a pty master with a + // 64 KiB buffer (`pty_chunk` in detached/server.zig, `[0x10000]u8` in + // tty.zig, gui.zig and macos.zig) and a single read really does return + // 65536 on Linux — measured. So a pane running a build or a `cat` of + // anything large produces exactly the record that empties the queue, + // repeatedly, for as long as a script holds `pty/data` open. + // + // The `event` queue never met this because its records are a few dozen + // bytes; `pty/data` inherited the cap without inheriting that property. + // Half the cap per record, so a full queue is at least two records and the + // eviction loop always has something to evict. + var off: usize = 0; + while (off < bytes.len) { + const n = @min(bytes.len - off, queue_cap / 2); + pf.pty_out.push(p.gpa, bytes[off..][0..n]); + off += n; + } } // ============================================================================ |
