aboutsummaryrefslogtreecommitdiff
path: root/src/watcher.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/watcher.zig')
-rw-r--r--src/watcher.zig90
1 files changed, 70 insertions, 20 deletions
diff --git a/src/watcher.zig b/src/watcher.zig
index 466463805..e3b3600ad 100644
--- a/src/watcher.zig
+++ b/src/watcher.zig
@@ -73,7 +73,7 @@ pub const INotify = struct {
// it includes alignment / padding
// but it is a sentineled value
// so we can just trim it to the first null byte
- return bun.sliceTo(@intToPtr([*:0]u8, @ptrToInt(&this.name_len) + @sizeOf(u32)), 0)[0.. :0];
+ return bun.sliceTo(@ptrFromInt([*:0]u8, @intFromPtr(&this.name_len) + @sizeOf(u32)), 0)[0.. :0];
}
};
pub var inotify_fd: EventListIndex = 0;
@@ -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,18 +369,22 @@ 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;
var evict_list: [WATCHER_MAX_LIST]WatchItemIndex = undefined;
pub fn getHash(filepath: string) HashType {
- return @truncate(HashType, std.hash.Wyhash.hash(0, filepath));
+ return @truncate(HashType, bun.hash(filepath));
}
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;
@@ -434,7 +478,7 @@ pub fn NewWatcher(comptime ContextType: type) type {
// swapRemove messes up the order
// But, it only messes up the order if any elements in the list appear after the item being removed
// So if we just sort the list by the biggest index first, that should be fine
- std.sort.sort(
+ std.sort.block(
WatchItemIndex,
evict_list[0..evict_list_i],
{},
@@ -530,8 +574,11 @@ 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 {
+ break;
+ }
}
} else if (Environment.isLinux) {
restart: while (true) {
@@ -543,14 +590,14 @@ pub fn NewWatcher(comptime ContextType: type) type {
// TODO: is this thread safe?
var remaining_events = events.len;
- var name_off: u8 = 0;
- var temp_name_list: [128]?[:0]u8 = undefined;
- var temp_name_off: u8 = 0;
-
const eventlist_index = this.watchlist.items(.eventlist_index);
while (remaining_events > 0) {
- const slice = events[0..@min(remaining_events, this.watch_events.len)];
+ var name_off: u8 = 0;
+ var temp_name_list: [128]?[:0]u8 = undefined;
+ var temp_name_off: u8 = 0;
+
+ const slice = events[0..@min(128, remaining_events, this.watch_events.len)];
var watchevents = this.watch_events[0..slice.len];
var watch_event_id: u32 = 0;
for (slice) |event| {
@@ -570,14 +617,14 @@ pub fn NewWatcher(comptime ContextType: type) type {
else
null;
watchevents[watch_event_id].name_off = temp_name_off;
- watchevents[watch_event_id].name_len = @as(u8, @boolToInt((event.name_len > 0)));
- temp_name_off += @as(u8, @boolToInt((event.name_len > 0)));
+ watchevents[watch_event_id].name_len = @as(u8, @intFromBool((event.name_len > 0)));
+ temp_name_off += @as(u8, @intFromBool((event.name_len > 0)));
watch_event_id += 1;
}
var all_events = watchevents[0..watch_event_id];
- std.sort.sort(WatchEvent, all_events, {}, WatchEvent.sortByIndex);
+ std.sort.block(WatchEvent, all_events, {}, WatchEvent.sortByIndex);
var last_event_index: usize = 0;
var last_event_id: INotify.EventListIndex = std.math.maxInt(INotify.EventListIndex);
@@ -600,8 +647,11 @@ 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);
+ if (this.running) {
+ this.ctx.onFileUpdate(all_events[0 .. last_event_index + 1], this.changed_filepaths[0 .. name_off + 1], this.watchlist);
+ } else {
+ break;
+ }
remaining_events -= slice.len;
}
}
@@ -859,7 +909,7 @@ pub fn NewWatcher(comptime ContextType: type) type {
}
}
}
- try this.watchlist.ensureUnusedCapacity(this.allocator, 1 + @intCast(usize, @boolToInt(parent_watch_item == null)));
+ try this.watchlist.ensureUnusedCapacity(this.allocator, 1 + @intCast(usize, @intFromBool(parent_watch_item == null)));
if (autowatch_parent_dir) {
parent_watch_item = parent_watch_item orelse try this.appendDirectoryAssumeCapacity(dir_fd, parent_dir, parent_dir_hash, copy_file_path);