authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-09 18:37:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-12 00:14:07-07:00
log6f89824c22b57e14951870c8f589df33e180f552
tree2051d9a71906490054cc8f40967b697c48f615db
parent5ee3971b1828468c89104cb01e19edc87edf35a6

build system: make debounce interval CLI-configurable


2 files changed, 12 insertions(+), 57 deletions(-)

lib/compiler/build_runner.zig+12-41
...@@ -107,6 +107,7 @@ pub fn main() !void {...@@ -107,6 +107,7 @@ pub fn main() !void {
107 var steps_menu = false;107 var steps_menu = false;
108 var output_tmp_nonce: ?[16]u8 = null;108 var output_tmp_nonce: ?[16]u8 = null;
109 var watch = false;109 var watch = false;
110 var debounce_interval_ms: u16 = 50;
110111
111 while (nextArg(args, &arg_idx)) |arg| {112 while (nextArg(args, &arg_idx)) |arg| {
112 if (mem.startsWith(u8, arg, "-Z")) {113 if (mem.startsWith(u8, arg, "-Z")) {
...@@ -194,7 +195,15 @@ pub fn main() !void {...@@ -194,7 +195,15 @@ pub fn main() !void {
194 const next_arg = nextArg(args, &arg_idx) orelse195 const next_arg = nextArg(args, &arg_idx) orelse
195 fatalWithHint("expected u32 after '{s}'", .{arg});196 fatalWithHint("expected u32 after '{s}'", .{arg});
196 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {197 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
197 fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{198 fatal("unable to parse seed '{s}' as unsigned 32-bit integer: {s}\n", .{
199 next_arg, @errorName(err),
200 });
201 };
202 } else if (mem.eql(u8, arg, "--debounce")) {
203 const next_arg = nextArg(args, &arg_idx) orelse
204 fatalWithHint("expected u16 after '{s}'", .{arg});
205 debounce_interval_ms = std.fmt.parseUnsigned(u16, next_arg, 0) catch |err| {
206 fatal("unable to parse debounce interval '{s}' as unsigned 16-bit integer: {s}\n", .{
198 next_arg, @errorName(err),207 next_arg, @errorName(err),
199 });208 });
200 };209 };
...@@ -473,7 +482,6 @@ pub fn main() !void {...@@ -473,7 +482,6 @@ pub fn main() !void {
473 // if any more events come in. After the debounce interval has passed,482 // if any more events come in. After the debounce interval has passed,
474 // trigger a rebuild on all steps with modified inputs, as well as their483 // trigger a rebuild on all steps with modified inputs, as well as their
475 // recursive dependants.484 // recursive dependants.
476 const debounce_interval_ms = 50;
477 var poll_fds: [1]std.posix.pollfd = .{485 var poll_fds: [1]std.posix.pollfd = .{
478 .{486 .{
479 .fd = w.fan_fd,487 .fd = w.fan_fd,
...@@ -515,67 +523,29 @@ fn markDirtySteps(w: *Watch) !bool {...@@ -515,67 +523,29 @@ fn markDirtySteps(w: *Watch) !bool {
515 error.WouldBlock => return any_dirty,523 error.WouldBlock => return any_dirty,
516 else => |e| return e,524 else => |e| return e,
517 };525 };
518 //std.debug.dump_hex(events_buf[0..len]);
519 var meta: [*]align(1) M = @ptrCast(&events_buf);526 var meta: [*]align(1) M = @ptrCast(&events_buf);
520 while (len >= @sizeOf(M) and meta[0].event_len >= @sizeOf(M) and meta[0].event_len <= len) : ({527 while (len >= @sizeOf(M) and meta[0].event_len >= @sizeOf(M) and meta[0].event_len <= len) : ({
521 len -= meta[0].event_len;528 len -= meta[0].event_len;
522 meta = @ptrCast(@as([*]u8, @ptrCast(meta)) + meta[0].event_len);529 meta = @ptrCast(@as([*]u8, @ptrCast(meta)) + meta[0].event_len);
523 }) {530 }) {
524 assert(meta[0].vers == M.VERSION);531 assert(meta[0].vers == M.VERSION);
525 std.debug.print("meta = {any}\n", .{meta[0]});
526 const fid: *align(1) fanotify.event_info_fid = @ptrCast(meta + 1);532 const fid: *align(1) fanotify.event_info_fid = @ptrCast(meta + 1);
527 switch (fid.hdr.info_type) {533 switch (fid.hdr.info_type) {
528 .DFID_NAME => {534 .DFID_NAME => {
529 const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle);535 const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle);
530 const file_name_z: [*:0]u8 = @ptrCast((&file_handle.f_handle).ptr + file_handle.handle_bytes);536 const file_name_z: [*:0]u8 = @ptrCast((&file_handle.f_handle).ptr + file_handle.handle_bytes);
531 const file_name = mem.span(file_name_z);537 const file_name = mem.span(file_name_z);
532 std.debug.print("DFID_NAME file_handle = {any}, found: '{s}'\n", .{ file_handle.*, file_name });
533 const lfh: Watch.LinuxFileHandle = .{ .handle = file_handle };538 const lfh: Watch.LinuxFileHandle = .{ .handle = file_handle };
534 if (w.handle_table.getPtr(lfh)) |reaction_set| {539 if (w.handle_table.getPtr(lfh)) |reaction_set| {
535 if (reaction_set.getPtr(file_name)) |step_set| {540 if (reaction_set.getPtr(file_name)) |step_set| {
536 for (step_set.keys()) |step| {541 for (step_set.keys()) |step| {
537 std.debug.print("DFID_NAME marking step '{s}' dirty\n", .{step.name});
538 step.state = .precheck_done;542 step.state = .precheck_done;
539 any_dirty = true;543 any_dirty = true;
540 }544 }
541 }545 }
542 } else {
543 std.debug.print("DFID_NAME changed file did not match any directories: '{}'\n", .{
544 std.fmt.fmtSliceHexLower(lfh.slice()),
545 });
546 }546 }
547 },547 },
548 //.FID => {548 else => |t| std.log.warn("unexpected fanotify event '{s}'", .{@tagName(t)}),
549 // const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle);
550 // const lfh: Watch.LinuxFileHandle = .{ .handle = file_handle };
551 // if (w.handle_table.get(lfh)) |step_set| {
552 // for (step_set.keys()) |step| {
553 // std.debug.print("FID marking step '{s}' dirty\n", .{step.name});
554 // step.state = .precheck_done;
555 // any_dirty = true;
556 // }
557 // } else {
558 // std.debug.print("FID changed file did not match any steps: '{}'\n", .{
559 // std.fmt.fmtSliceHexLower(lfh.slice()),
560 // });
561 // }
562 //},
563 //.DFID => {
564 // const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle);
565 // const lfh: Watch.LinuxFileHandle = .{ .handle = file_handle };
566 // if (w.handle_table.get(lfh)) |step_set| {
567 // for (step_set.keys()) |step| {
568 // std.debug.print("DFID marking step '{s}' dirty\n", .{step.name});
569 // step.state = .precheck_done;
570 // any_dirty = true;
571 // }
572 // } else {
573 // std.debug.print("DFID changed file did not match any steps\n", .{});
574 // }
575 //},
576 else => |t| {
577 std.debug.panic("TODO: received event type '{s}'", .{@tagName(t)});
578 },
579 }549 }
580 }550 }
581 }551 }
...@@ -1349,6 +1319,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {...@@ -1349,6 +1319,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
1349 \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss1319 \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
1350 \\ --fetch Exit after fetching dependency tree1320 \\ --fetch Exit after fetching dependency tree
1351 \\ --watch Continuously rebuild when source files are modified1321 \\ --watch Continuously rebuild when source files are modified
1322 \\ --debounce <ms> Delay before rebuilding after watched file detection
1352 \\1323 \\
1353 \\Project-Specific Options:1324 \\Project-Specific Options:
1354 \\1325 \\
lib/std/Build/Watch.zig-16
...@@ -104,22 +104,6 @@ pub const LinuxFileHandle = struct {...@@ -104,22 +104,6 @@ pub const LinuxFileHandle = struct {
104 };104 };
105};105};
106106
107pub fn getFileHandle(gpa: Allocator, path: std.Build.Cache.Path, basename: []const u8) !LinuxFileHandle {
108 var file_handle_buffer: [@sizeOf(std.os.linux.file_handle) + 128]u8 align(@alignOf(std.os.linux.file_handle)) = undefined;
109 var mount_id: i32 = undefined;
110 var buf: [std.fs.max_path_bytes]u8 = undefined;
111 const joined_path = if (path.sub_path.len == 0) basename else path: {
112 break :path std.fmt.bufPrint(&buf, "{s}/{s}", .{
113 path.sub_path, basename,
114 }) catch return error.NameTooLong;
115 };
116 const stack_ptr: *std.os.linux.file_handle = @ptrCast(&file_handle_buffer);
117 stack_ptr.handle_bytes = file_handle_buffer.len - @sizeOf(std.os.linux.file_handle);
118 try std.posix.name_to_handle_at(path.root_dir.handle.fd, joined_path, stack_ptr, &mount_id, 0);
119 const stack_lfh: LinuxFileHandle = .{ .handle = stack_ptr };
120 return stack_lfh.clone(gpa);
121}
122
123pub fn getDirHandle(gpa: Allocator, path: std.Build.Cache.Path) !LinuxFileHandle {107pub fn getDirHandle(gpa: Allocator, path: std.Build.Cache.Path) !LinuxFileHandle {
124 var file_handle_buffer: [@sizeOf(std.os.linux.file_handle) + 128]u8 align(@alignOf(std.os.linux.file_handle)) = undefined;108 var file_handle_buffer: [@sizeOf(std.os.linux.file_handle) + 128]u8 align(@alignOf(std.os.linux.file_handle)) = undefined;
125 var mount_id: i32 = undefined;109 var mount_id: i32 = undefined;