diff options
Diffstat (limited to 'src/tty')
| -rw-r--r-- | src/tty/tty.zig | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/src/tty/tty.zig b/src/tty/tty.zig index f8f7150b..e8a36035 100644 --- a/src/tty/tty.zig +++ b/src/tty/tty.zig @@ -11,7 +11,6 @@ const std = @import("std"); const builtin = @import("builtin"); const posix = std.posix; const libc = std.c; -const linux = std.os.linux; const vaxis = @import("vaxis"); const pardes = @import("../pardes.zig"); const tracy = @import("../tracy.zig"); @@ -343,8 +342,8 @@ test "Kitty PDF fragments never declare pixels beyond their clipped bottom" { try std.testing.expect(kittyPlacement(height, 80, 16, 640, 256) == null); } -test "Linux host watch closes initial race and reloads rename-over PDF while idle" { - if (comptime builtin.os.tag != .linux or !pardes.pdf_enabled) return; +test "host watch closes initial race and reloads rename-over PDF while idle" { + if (comptime !file_watch.supported or !pardes.pdf_enabled) return; const io = std.testing.io; const gpa = std.testing.allocator; var tmp = std.testing.tmpDir(.{}); @@ -361,8 +360,8 @@ test "Linux host watch closes initial race and reloads rename-over PDF while idl var path_buf: [256]u8 = undefined; const path = try std.fmt.bufPrint(&path_buf, ".zig-cache/tmp/{s}/live.pdf", .{tmp.sub_path}); - const fd = libc.inotify_init1(linux.IN.CLOEXEC | linux.IN.NONBLOCK); - if (fd < 0) return error.InotifyInitFailed; + const fd = file_watch.init(true); + if (fd < 0) return error.WatchInitFailed; defer _ = libc.close(fd); var watches: file_watch.Table = @splat(null); defer for (0..pardes.MAX_PANES) |id| file_watch.watchPane( @@ -394,9 +393,7 @@ test "Linux host watch closes initial race and reloads rename-over PDF while idl try std.testing.expectEqual(@as(usize, 1), core.panes[0].?.pdf.?.page_count); try tmp.dir.rename("live-replacement.pdf", tmp.dir, "live.pdf", io); - var events: [4096]u8 = undefined; - const event_bytes = libc.read(fd, &events, events.len); - try std.testing.expect(event_bytes > 0); + try std.testing.expect(file_watch.drain(fd)); // This is the same pass the watcher thread schedules; no key, mouse, or // synthetic core file_changed event participates in the transaction. @@ -699,11 +696,12 @@ fn localSession( .kitty = kitty_handles, .frame = &frame_arena, .paste_buf = paste_buf, - // One inotify instance for every watched pane, opened here — before - // any thread exists — so the pre-loop effect drain below can already - // mark the file a positional path argument opened. -1 off linux: + // One watcher for every watched pane, opened here — before any thread + // exists — so the pre-loop effect drain below can already mark the file + // a positional path argument opened. `false`: this host parks a thread + // in it rather than polling it. -1 where there is no watcher to make: // watchPane goes quiet and the core simply never gets a file_changed. - .inotify_fd = if (builtin.os.tag == .linux) libc.inotify_init1(linux.IN.CLOEXEC) else -1, + .inotify_fd = file_watch.init(false), .fs = fs, }; // The protocol client's reader threads narrate server state through this @@ -746,8 +744,10 @@ fn localSession( sh.lsp_task = null; } sh.pipe_tasks.cancelAll(io); - // same contract as the pty readers: cancel unblocks the watcher's - // read, and only then is the fd safe to close + // same contract as the pty readers: the watcher has to be off the + // descriptor before it is closed. `stop` is what releases a kqueue wait + // (macos); `cancel` is what interrupts the blocking read (linux). + file_watch.stop(sh.inotify_fd); if (sh.watch_task) |*t| { t.cancel(io) catch {}; sh.watch_task = null; @@ -1679,6 +1679,13 @@ fn pipeWorker( /// per open file pane; filter by basename here if it ever shows up in a /// profile. fn watchFiles(io: std.Io, fd: c_int, loop: *Loop) anyerror!void { + // A kqueue cannot be read, so there is no std.Io.File to wrap and no + // `cancel` to interrupt: this arm parks in kevent(2) and the teardown's + // `file_watch.stop` is what releases it. See file_watch.wait. + if (comptime builtin.os.tag != .linux) { + while (file_watch.wait(fd)) loop.postEvent(.files_changed) catch break; + return; + } const file: std.Io.File = .{ .handle = fd, .flags = .{ .nonblocking = false } }; var read_buf: [4096]u8 = undefined; var reader = file.readerStreaming(io, &read_buf); |
