aboutsummaryrefslogtreecommitdiff
path: root/src/watcher.zig
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/watcher.zig153
1 files changed, 86 insertions, 67 deletions
diff --git a/src/watcher.zig b/src/watcher.zig
index 105c29b12..7805222f2 100644
--- a/src/watcher.zig
+++ b/src/watcher.zig
@@ -5,6 +5,7 @@ const options = @import("./options.zig");
const IndexType = @import("./allocators.zig").IndexType;
const os = std.os;
+
const KEvent = std.os.Kevent;
const Mutex = @import("./lock.zig").Lock;
@@ -12,6 +13,8 @@ const WatchItemIndex = u16;
const NoWatchItem: WatchItemIndex = std.math.maxInt(WatchItemIndex);
const PackageJSON = @import("./resolver/package_json.zig").PackageJSON;
+const WATCHER_MAX_LIST = 8096;
+
pub const WatchItem = struct {
file_path: string,
// filepath hash for quick comparison
@@ -49,6 +52,20 @@ pub const WatchEvent = struct {
pub const Watchlist = std.MultiArrayList(WatchItem);
+const DarwinWatcher = struct {
+
+ // Internal
+ changelist: [128]KEvent = undefined,
+
+ // Everything being watched
+ eventlist: [WATCHER_MAX_LIST]KEvent = undefined,
+};
+
+const PlatformWatcher = if (Environment.isMac)
+ DarwinWatcher
+else
+ void;
+
// This implementation only works on macOS, for now.
// The Internet seems to suggest basically always using FSEvents instead of kqueue
// It seems like the main concern is max open file descriptors
@@ -57,23 +74,17 @@ pub fn NewWatcher(comptime ContextType: type) type {
return struct {
const Watcher = @This();
- const KEventArrayList = std.ArrayList(KEvent);
- const WATCHER_MAX_LIST = 8096;
-
watchlist: Watchlist,
watched_count: usize = 0,
mutex: Mutex,
- // Internal
- changelist: [128]KEvent = undefined,
+ eventlist_used: usize = 0,
+
+ platform: PlatformWatcher = PlatformWatcher{},
// User-facing
watch_events: [128]WatchEvent = undefined,
- // Everything being watched
- eventlist: [WATCHER_MAX_LIST]KEvent = undefined,
- eventlist_used: usize = 0,
-
fs: *Fs.FileSystem,
// this is what kqueue knows about
fd: StoredFileDescriptorType,
@@ -108,9 +119,11 @@ pub fn NewWatcher(comptime ContextType: type) type {
pub fn getQueue(this: *Watcher) !StoredFileDescriptorType {
if (this.fd == 0) {
- this.fd = try os.kqueue();
- if (this.fd == 0) {
- return error.WatcherFailed;
+ if (Environment.isMac) {
+ this.fd = try os.kqueue();
+ if (this.fd == 0) {
+ return error.WatcherFailed;
+ }
}
}
@@ -202,28 +215,31 @@ pub fn NewWatcher(comptime ContextType: type) type {
fn _watchLoop(this: *Watcher) !void {
const time = std.time;
- std.debug.assert(this.fd > 0);
+ if (Environment.isMac) {
+ std.debug.assert(this.fd > 0);
- var changelist_array: [1]KEvent = std.mem.zeroes([1]KEvent);
- var changelist = &changelist_array;
- while (true) {
- defer Output.flush();
- var code = std.os.system.kevent(
- try this.getQueue(),
- @as([*]KEvent, changelist),
- 0,
- @as([*]KEvent, changelist),
- 1,
+ var changelist_array: [1]KEvent = std.mem.zeroes([1]KEvent);
+ var changelist = &changelist_array;
+ while (true) {
+ defer Output.flush();
- null,
- );
+ _ = std.os.system.kevent(
+ try this.getQueue(),
+ @as([*]KEvent, changelist),
+ 0,
+ @as([*]KEvent, changelist),
+ 1,
- var watchevents = this.watch_events[0..1];
- for (changelist) |event, i| {
- watchevents[i].fromKEvent(&event);
- }
+ null,
+ );
+
+ var watchevents = this.watch_events[0..1];
+ for (changelist) |event, i| {
+ watchevents[i].fromKEvent(&event);
+ }
- this.ctx.onFileUpdate(watchevents, this.watchlist);
+ this.ctx.onFileUpdate(watchevents, this.watchlist);
+ }
}
}
@@ -266,7 +282,7 @@ pub fn NewWatcher(comptime ContextType: type) type {
const index = this.eventlist_used;
const watchlist_id = this.watchlist.len;
- if (isMac) {
+ if (Environment.isMac) {
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
var event = std.mem.zeroes(KEvent);
@@ -290,7 +306,7 @@ pub fn NewWatcher(comptime ContextType: type) type {
// Store the hash for fast filtering later
event.udata = @intCast(usize, watchlist_id);
- this.eventlist[index] = event;
+ this.platform.eventlist[index] = event;
// This took a lot of work to figure out the right permutation
// Basically:
@@ -298,9 +314,9 @@ pub fn NewWatcher(comptime ContextType: type) type {
// our while(true) loop above receives notification of changes to any of the events created here.
_ = std.os.system.kevent(
try this.getQueue(),
- this.eventlist[index .. index + 1].ptr,
+ this.platform.eventlist[index .. index + 1].ptr,
1,
- this.eventlist[index .. index + 1].ptr,
+ this.platform.eventlist[index .. index + 1].ptr,
0,
null,
);
@@ -337,39 +353,42 @@ pub fn NewWatcher(comptime ContextType: type) type {
const index = this.eventlist_used;
const watchlist_id = this.watchlist.len;
- // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
- var event = std.mem.zeroes(KEvent);
-
- event.flags = os.EV_ADD | os.EV_CLEAR | os.EV_ENABLE;
- // we want to know about the vnode
- event.filter = std.os.EVFILT_VNODE;
-
- // monitor:
- // - Write
- // - Rename
- // - Delete
- event.fflags = std.os.NOTE_WRITE | std.os.NOTE_RENAME | std.os.NOTE_DELETE;
-
- // id
- event.ident = @intCast(usize, fd);
-
- this.eventlist_used += 1;
- // Store the hash for fast filtering later
- event.udata = @intCast(usize, watchlist_id);
- this.eventlist[index] = event;
-
- // This took a lot of work to figure out the right permutation
- // Basically:
- // - We register the event here.
- // our while(true) loop above receives notification of changes to any of the events created here.
- _ = std.os.system.kevent(
- try this.getQueue(),
- this.eventlist[index .. index + 1].ptr,
- 1,
- this.eventlist[index .. index + 1].ptr,
- 0,
- null,
- );
+ if (Environment.isMac) {
+
+ // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
+ var event = std.mem.zeroes(KEvent);
+
+ event.flags = os.EV_ADD | os.EV_CLEAR | os.EV_ENABLE;
+ // we want to know about the vnode
+ event.filter = std.os.EVFILT_VNODE;
+
+ // monitor:
+ // - Write
+ // - Rename
+ // - Delete
+ event.fflags = std.os.NOTE_WRITE | std.os.NOTE_RENAME | std.os.NOTE_DELETE;
+
+ // id
+ event.ident = @intCast(usize, fd);
+
+ this.eventlist_used += 1;
+ // Store the hash for fast filtering later
+ event.udata = @intCast(usize, watchlist_id);
+ this.platform.eventlist[index] = event;
+
+ // This took a lot of work to figure out the right permutation
+ // Basically:
+ // - We register the event here.
+ // our while(true) loop above receives notification of changes to any of the events created here.
+ _ = std.os.system.kevent(
+ try this.getQueue(),
+ this.platform.eventlist[index .. index + 1].ptr,
+ 1,
+ this.platform.eventlist[index .. index + 1].ptr,
+ 0,
+ null,
+ );
+ }
this.watchlist.appendAssumeCapacity(.{
.file_path = if (copy_file_path) try this.allocator.dupe(u8, file_path) else file_path,