summaryrefslogtreecommitdiff
path: root/src/detached
diff options
context:
space:
mode:
Diffstat (limited to 'src/detached')
-rw-r--r--src/detached/client.zig17
-rw-r--r--src/detached/server.zig18
2 files changed, 20 insertions, 15 deletions
diff --git a/src/detached/client.zig b/src/detached/client.zig
index 4769cf25..fc39164b 100644
--- a/src/detached/client.zig
+++ b/src/detached/client.zig
@@ -1129,9 +1129,20 @@ test "detached session: a frontend that stops reading is dropped, not waited for
for (0..24) |_| {
if (!h.session.clients[1].attached) break;
host.vtable.push_set_clipboard.?(host.ctx, text);
- try h.pump();
- try good.wait(5);
- while (try good.next()) |_| {}
+ // Read `good` back to EMPTY before the next mirror, rather than
+ // pumping once and taking whatever one write fitted. One pump moves at
+ // most one socket buffer, and that buffer is 8 KiB here
+ // (`net.local.stream.sendspace` on Darwin) against Linux's 208 KiB —
+ // so a single pump per 256 KiB mirror leaves the READING frontend
+ // falling behind by a quarter megabyte a round and closes it for a
+ // backlog it never caused. The claim under test is that a frontend
+ // that reads survives, so it has to actually finish reading.
+ for (0..256) |_| {
+ try h.pump();
+ try good.wait(5);
+ while (try good.next()) |_| {}
+ if (h.session.clients[0].out.items.len == 0) break;
+ }
}
// Dropped rather than queued without bound, and rather than the core
// blocking on it.
diff --git a/src/detached/server.zig b/src/detached/server.zig
index 7d286177..2c4df87b 100644
--- a/src/detached/server.zig
+++ b/src/detached/server.zig
@@ -141,7 +141,6 @@
const std = @import("std");
const builtin = @import("builtin");
const libc = std.c;
-const linux = std.os.linux;
const posix = std.posix;
const pardes = @import("../pardes.zig");
const host_api = @import("../host.zig");
@@ -1221,17 +1220,13 @@ pub const Session = struct {
/// then keeps its own record of what was asked and simply never gets a
/// reload, which is what a host with no watcher has always done.
///
- /// NONBLOCK because this descriptor is drained from `poll`, not from a
- /// thread parked in `read` (tty.zig `watchFiles`): `drainInotify` must be
- /// able to stop.
+ /// `polled` is true because this descriptor is drained from `poll`, not
+ /// from a thread parked in a wait (tty.zig `watchFiles`): `drainInotify`
+ /// must be able to stop. On linux that is IN_NONBLOCK; on macos a kqueue
+ /// needs nothing, since the timeout argument to `kevent(2)` decides.
fn inotify(s: *Session) c_int {
if (s.inotify_fd >= 0) return s.inotify_fd;
- // The whole body is inside the comptime branch so that neither
- // `inotify_init1` nor `linux.IN` is even analysed on a platform that has
- // no inotify — the same shape file_watch.zig's `watchPath` uses.
- if (comptime builtin.os.tag == .linux) {
- s.inotify_fd = libc.inotify_init1(linux.IN.CLOEXEC | linux.IN.NONBLOCK);
- }
+ s.inotify_fd = file_watch.init(true);
return s.inotify_fd;
}
@@ -1252,8 +1247,7 @@ pub const Session = struct {
/// frontend got a frame per round it could not use. The fd is IN_NONBLOCK
/// (`inotify`), so the loop ends on EAGAIN.
fn drainInotify(s: *Session) void {
- var buf: [4096]u8 = undefined;
- while (libc.read(s.inotify_fd, &buf, buf.len) > 0) s.check_files = true;
+ if (file_watch.drain(s.inotify_fd)) s.check_files = true;
}
/// Reconcile every marked pane and the theme file. Called at the END of