aboutsummaryrefslogtreecommitdiff
path: root/src/watcher.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/watcher.zig')
-rw-r--r--src/watcher.zig68
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;
+ }
}
}
}