aboutsummaryrefslogtreecommitdiff
path: root/src/watcher.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/watcher.zig')
-rw-r--r--src/watcher.zig53
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, &timespec, 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,