diff options
Diffstat (limited to 'src/watcher.zig')
-rw-r--r-- | src/watcher.zig | 90 |
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); |