diff options
Diffstat (limited to 'src/watcher.zig')
-rw-r--r-- | src/watcher.zig | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/src/watcher.zig b/src/watcher.zig index 2a20c0db3..7d610088d 100644 --- a/src/watcher.zig +++ b/src/watcher.zig @@ -68,24 +68,25 @@ pub const INotify = struct { pub fn name(this: *const INotifyEvent) [:0]u8 { if (comptime Environment.allow_assert) std.debug.assert(this.name_len > 0); + // the name_len field is wrong // it includes alignment / padding // but it is a sentineled value // so we can just trim it to the first null byte - return std.mem.sliceTo(@intToPtr([*]u8, @ptrToInt(this) + @sizeOf(INotifyEvent))[0..this.name_len :0], 0); + return bun.sliceTo(@intToPtr([*:0]u8, @ptrToInt(&this.name_len) + @sizeOf(u32)), 0)[0.. :0]; } }; pub var inotify_fd: EventListIndex = 0; pub var loaded_inotify = false; - const EventListBuffer = [@sizeOf([128]INotifyEvent) + (128 * bun.MAX_PATH_BYTES)]u8; + const EventListBuffer = [@sizeOf([128]INotifyEvent) + (128 * bun.MAX_PATH_BYTES + (128 * @alignOf(INotifyEvent)))]u8; var eventlist: EventListBuffer = undefined; var eventlist_ptrs: [128]*const INotifyEvent = undefined; var watch_count: std.atomic.Atomic(u32) = std.atomic.Atomic(u32).init(0); - const watch_file_mask = IN_EXCL_UNLINK | IN_MOVE_SELF | IN_DELETE_SELF | IN_CLOSE_WRITE | IN_MOVED_TO; - const watch_dir_mask = IN_EXCL_UNLINK | IN_DELETE | IN_DELETE_SELF | IN_CREATE | IN_MOVE_SELF | IN_ONLYDIR | IN_MOVED_TO; + const watch_file_mask = std.os.linux.IN.EXCL_UNLINK | std.os.linux.IN.MOVE_SELF | std.os.linux.IN.DELETE_SELF | std.os.linux.IN.MOVED_TO | std.os.linux.IN.MODIFY; + const watch_dir_mask = std.os.linux.IN.EXCL_UNLINK | std.os.linux.IN.DELETE | std.os.linux.IN.DELETE_SELF | std.os.linux.IN.CREATE | std.os.linux.IN.MOVE_SELF | std.os.linux.IN.ONLYDIR | std.os.linux.IN.MOVED_TO; pub fn watchPath(pathname: [:0]const u8) !EventListIndex { std.debug.assert(loaded_inotify); @@ -127,14 +128,46 @@ pub const INotify = struct { switch (std.os.errno(rc)) { .SUCCESS => { - const len = @intCast(usize, rc); + var len = @intCast(usize, rc); if (len == 0) return &[_]*INotifyEvent{}; + // IN_MODIFY is very noisy + // we do a 0.1ms sleep to try to coalesce events better + if (len < (@sizeOf(EventListBuffer) / 2)) { + var fds = [_]std.os.pollfd{.{ + .fd = inotify_fd, + .events = std.os.POLL.IN | std.os.POLL.ERR, + .revents = 0, + }}; + var timespec = std.os.timespec{ .tv_sec = 0, .tv_nsec = 100_000 }; + if ((std.os.ppoll(&fds, ×pec, null) catch 0) > 0) { + while (true) { + const new_rc = std.os.system.read( + inotify_fd, + @ptrCast([*]u8, @alignCast(@alignOf([*]u8), &eventlist)) + len, + @sizeOf(EventListBuffer) - len, + ); + switch (std.os.errno(new_rc)) { + .SUCCESS => { + len += @intCast(usize, new_rc); + }, + .AGAIN => continue, + .INTR => continue, + .INVAL => return error.ShortRead, + .BADF => return error.INotifyFailedToStart, + else => unreachable, + } + break; + } + } + } + var count: u32 = 0; var i: u32 = 0; while (i < len) : (i += @sizeOf(INotifyEvent)) { - const event = @ptrCast(*const INotifyEvent, @alignCast(@alignOf(*const INotifyEvent), eventlist[i..][0..@sizeOf(INotifyEvent)])); + @setRuntimeSafety(false); + var event = @ptrCast(*INotifyEvent, @alignCast(@alignOf(*INotifyEvent), eventlist[i..][0..@sizeOf(INotifyEvent)])); i += event.name_len; eventlist_ptrs[count] = event; @@ -225,6 +258,12 @@ pub const WatchEvent = struct { name_off: u8 = 0, name_len: u8 = 0, + pub fn ignoreINotifyEvent(event: INotify.INotifyEvent) bool { + var stack: WatchEvent = undefined; + stack.fromINotify(event, 0); + return @bitCast(std.meta.Int(.unsigned, @bitSizeOf(Op)), stack.op) == 0; + } + pub fn names(this: WatchEvent, buf: []?[:0]u8) []?[:0]u8 { if (this.name_len == 0) return &[_]?[:0]u8{}; return buf[this.name_off..][0..this.name_len]; @@ -275,8 +314,6 @@ pub const WatchEvent = struct { } pub const Op = packed struct { - padding: u3 = 0, - delete: bool = false, metadata: bool = false, rename: bool = false, |