diff options
Diffstat (limited to 'src/watcher.zig')
-rw-r--r-- | src/watcher.zig | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/src/watcher.zig b/src/watcher.zig index 155c0b473..044770dc4 100644 --- a/src/watcher.zig +++ b/src/watcher.zig @@ -108,6 +108,10 @@ pub const INotify = struct { std.os.inotify_rm_watch(inotify_fd, wd); } + pub fn isRunning() bool { + return loaded_inotify; + } + var coalesce_interval: isize = 100_000; pub fn init() !void { std.debug.assert(!loaded_inotify); @@ -229,6 +233,10 @@ const DarwinWatcher = struct { if (fd == 0) return error.KQueueError; } + pub fn isRunning() bool { + return fd != 0; + } + pub fn stop() void { if (fd != 0) { std.os.close(fd); @@ -361,6 +369,8 @@ pub fn NewWatcher(comptime ContextType: type) type { watchloop_handle: ?std.Thread.Id = null, cwd: string, thread: std.Thread = undefined, + running: bool = true, + close_descriptors: bool = false, pub const HashType = u32; @@ -372,7 +382,9 @@ pub fn NewWatcher(comptime ContextType: type) type { pub fn init(ctx: ContextType, fs: *Fs.FileSystem, allocator: std.mem.Allocator) !*Watcher { var watcher = try allocator.create(Watcher); - try PlatformWatcher.init(); + if (!PlatformWatcher.isRunning()) { + try PlatformWatcher.init(); + } watcher.* = Watcher{ .fs = fs, @@ -393,6 +405,26 @@ pub fn NewWatcher(comptime ContextType: type) type { this.thread = try std.Thread.spawn(.{}, Watcher.watchLoop, .{this}); } + pub fn deinit(this: *Watcher, close_descriptors: bool) void { + this.mutex.lock(); + defer this.mutex.unlock(); + + this.close_descriptors = close_descriptors; + if (this.watchloop_handle != null) { + this.running = false; + } else { + if (this.close_descriptors and this.running) { + const fds = this.watchlist.items(.fd); + for (fds) |fd| { + std.os.close(fd); + } + } + this.watchlist.deinit(this.allocator); + const allocator = this.allocator; + allocator.destroy(this); + } + } + // This must only be called from the watcher thread pub fn watchLoop(this: *Watcher) !void { this.watchloop_handle = std.Thread.getCurrentId(); @@ -402,12 +434,24 @@ pub fn NewWatcher(comptime ContextType: type) type { if (FeatureFlags.verbose_watcher) Output.prettyln("Watcher started", .{}); this._watchLoop() catch |err| { - Output.prettyErrorln("<r>Watcher crashed: <red><b>{s}<r>", .{@errorName(err)}); - this.watchloop_handle = null; PlatformWatcher.stop(); - return; + if (this.running) { + this.ctx.onError(err); + } }; + + // deinit and close descriptors if needed + if (this.close_descriptors) { + const fds = this.watchlist.items(.fd); + for (fds) |fd| { + std.os.close(fd); + } + } + this.watchlist.deinit(this.allocator); + + const allocator = this.allocator; + allocator.destroy(this); } var evict_list_i: WatchItemIndex = 0; @@ -475,7 +519,7 @@ pub fn NewWatcher(comptime ContextType: type) type { var changelist_array: [128]KEvent = std.mem.zeroes([128]KEvent); var changelist = &changelist_array; - while (true) { + while (this.running) { defer Output.flush(); var count_ = std.os.system.kevent( @@ -530,11 +574,12 @@ pub fn NewWatcher(comptime ContextType: type) type { this.mutex.lock(); defer this.mutex.unlock(); - - this.ctx.onFileUpdate(watchevents, this.changed_filepaths[0..watchevents.len], this.watchlist); + if (this.running) { + this.ctx.onFileUpdate(watchevents, this.changed_filepaths[0..watchevents.len], this.watchlist); + } } } else if (Environment.isLinux) { - restart: while (true) { + restart: while (this.running) { defer Output.flush(); var events = try INotify.read(); @@ -600,9 +645,10 @@ pub fn NewWatcher(comptime ContextType: type) type { this.mutex.lock(); defer this.mutex.unlock(); - - this.ctx.onFileUpdate(all_events[0 .. last_event_index + 1], this.changed_filepaths[0 .. name_off + 1], this.watchlist); - remaining_events -= slice.len; + if (this.running) { + this.ctx.onFileUpdate(all_events[0 .. last_event_index + 1], this.changed_filepaths[0 .. name_off + 1], this.watchlist); + remaining_events -= slice.len; + } } } } |