mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std.Build.Watch: make dirty steps invalidate each other
and make failed steps always be invalidated and make steps that don't need to be reevaluated marked as cached
This commit is contained in:
parent
6f89824c22
commit
001ff7b3b2
3 changed files with 82 additions and 40 deletions
|
|
@ -500,9 +500,10 @@ pub fn main() !void {
|
||||||
const events_len = try std.posix.poll(&poll_fds, timeout);
|
const events_len = try std.posix.poll(&poll_fds, timeout);
|
||||||
if (events_len == 0) {
|
if (events_len == 0) {
|
||||||
debouncing_node.end();
|
debouncing_node.end();
|
||||||
|
Watch.markFailedStepsDirty(gpa, run.step_stack.keys());
|
||||||
continue :rebuild;
|
continue :rebuild;
|
||||||
}
|
}
|
||||||
if (try markDirtySteps(&w)) {
|
if (try w.markDirtySteps(gpa)) {
|
||||||
if (!debouncing) {
|
if (!debouncing) {
|
||||||
debouncing = true;
|
debouncing = true;
|
||||||
debouncing_node.end();
|
debouncing_node.end();
|
||||||
|
|
@ -513,44 +514,6 @@ pub fn main() !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn markDirtySteps(w: *Watch) !bool {
|
|
||||||
const fanotify = std.os.linux.fanotify;
|
|
||||||
const M = fanotify.event_metadata;
|
|
||||||
var events_buf: [256 + 4096]u8 = undefined;
|
|
||||||
var any_dirty = false;
|
|
||||||
while (true) {
|
|
||||||
var len = std.posix.read(w.fan_fd, &events_buf) catch |err| switch (err) {
|
|
||||||
error.WouldBlock => return any_dirty,
|
|
||||||
else => |e| return e,
|
|
||||||
};
|
|
||||||
var meta: [*]align(1) M = @ptrCast(&events_buf);
|
|
||||||
while (len >= @sizeOf(M) and meta[0].event_len >= @sizeOf(M) and meta[0].event_len <= len) : ({
|
|
||||||
len -= meta[0].event_len;
|
|
||||||
meta = @ptrCast(@as([*]u8, @ptrCast(meta)) + meta[0].event_len);
|
|
||||||
}) {
|
|
||||||
assert(meta[0].vers == M.VERSION);
|
|
||||||
const fid: *align(1) fanotify.event_info_fid = @ptrCast(meta + 1);
|
|
||||||
switch (fid.hdr.info_type) {
|
|
||||||
.DFID_NAME => {
|
|
||||||
const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle);
|
|
||||||
const file_name_z: [*:0]u8 = @ptrCast((&file_handle.f_handle).ptr + file_handle.handle_bytes);
|
|
||||||
const file_name = mem.span(file_name_z);
|
|
||||||
const lfh: Watch.LinuxFileHandle = .{ .handle = file_handle };
|
|
||||||
if (w.handle_table.getPtr(lfh)) |reaction_set| {
|
|
||||||
if (reaction_set.getPtr(file_name)) |step_set| {
|
|
||||||
for (step_set.keys()) |step| {
|
|
||||||
step.state = .precheck_done;
|
|
||||||
any_dirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => |t| std.log.warn("unexpected fanotify event '{s}'", .{@tagName(t)}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Run = struct {
|
const Run = struct {
|
||||||
max_rss: u64,
|
max_rss: u64,
|
||||||
max_rss_is_default: bool,
|
max_rss_is_default: bool,
|
||||||
|
|
@ -1319,7 +1282,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
|
||||||
\\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
|
\\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
|
||||||
\\ --fetch Exit after fetching dependency tree
|
\\ --fetch Exit after fetching dependency tree
|
||||||
\\ --watch Continuously rebuild when source files are modified
|
\\ --watch Continuously rebuild when source files are modified
|
||||||
\\ --debounce <ms> Delay before rebuilding after watched file detection
|
\\ --debounce <ms> Delay before rebuilding after changed file detected
|
||||||
\\
|
\\
|
||||||
\\Project-Specific Options:
|
\\Project-Specific Options:
|
||||||
\\
|
\\
|
||||||
|
|
|
||||||
|
|
@ -637,6 +637,31 @@ fn addWatchInputFromPath(step: *Step, path: Build.Cache.Path, basename: []const
|
||||||
try gop.value_ptr.append(gpa, basename);
|
try gop.value_ptr.append(gpa, basename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reset(step: *Step, gpa: Allocator) void {
|
||||||
|
assert(step.state == .precheck_done);
|
||||||
|
|
||||||
|
step.result_error_msgs.clearRetainingCapacity();
|
||||||
|
step.result_stderr = "";
|
||||||
|
step.result_cached = false;
|
||||||
|
step.result_duration_ns = null;
|
||||||
|
step.result_peak_rss = 0;
|
||||||
|
step.test_results = .{};
|
||||||
|
|
||||||
|
step.result_error_bundle.deinit(gpa);
|
||||||
|
step.result_error_bundle = std.zig.ErrorBundle.empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation detail of file watching. Prepares the step for being re-evaluated.
|
||||||
|
pub fn recursiveReset(step: *Step, gpa: Allocator) void {
|
||||||
|
assert(step.state != .precheck_done);
|
||||||
|
step.state = .precheck_done;
|
||||||
|
step.reset(gpa);
|
||||||
|
for (step.dependants.items) |dep| {
|
||||||
|
if (dep.state == .precheck_done) continue;
|
||||||
|
dep.recursiveReset(gpa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = CheckFile;
|
_ = CheckFile;
|
||||||
_ = CheckObject;
|
_ = CheckObject;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ const std = @import("../std.zig");
|
||||||
const Watch = @This();
|
const Watch = @This();
|
||||||
const Step = std.Build.Step;
|
const Step = std.Build.Step;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
dir_table: DirTable,
|
dir_table: DirTable,
|
||||||
/// Keyed differently but indexes correspond 1:1 with `dir_table`.
|
/// Keyed differently but indexes correspond 1:1 with `dir_table`.
|
||||||
|
|
@ -117,3 +118,56 @@ pub fn getDirHandle(gpa: Allocator, path: std.Build.Cache.Path) !LinuxFileHandle
|
||||||
const stack_lfh: LinuxFileHandle = .{ .handle = stack_ptr };
|
const stack_lfh: LinuxFileHandle = .{ .handle = stack_ptr };
|
||||||
return stack_lfh.clone(gpa);
|
return stack_lfh.clone(gpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn markDirtySteps(w: *Watch, gpa: Allocator) !bool {
|
||||||
|
const fanotify = std.os.linux.fanotify;
|
||||||
|
const M = fanotify.event_metadata;
|
||||||
|
var events_buf: [256 + 4096]u8 = undefined;
|
||||||
|
var any_dirty = false;
|
||||||
|
while (true) {
|
||||||
|
var len = std.posix.read(w.fan_fd, &events_buf) catch |err| switch (err) {
|
||||||
|
error.WouldBlock => return any_dirty,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
|
var meta: [*]align(1) M = @ptrCast(&events_buf);
|
||||||
|
while (len >= @sizeOf(M) and meta[0].event_len >= @sizeOf(M) and meta[0].event_len <= len) : ({
|
||||||
|
len -= meta[0].event_len;
|
||||||
|
meta = @ptrCast(@as([*]u8, @ptrCast(meta)) + meta[0].event_len);
|
||||||
|
}) {
|
||||||
|
assert(meta[0].vers == M.VERSION);
|
||||||
|
const fid: *align(1) fanotify.event_info_fid = @ptrCast(meta + 1);
|
||||||
|
switch (fid.hdr.info_type) {
|
||||||
|
.DFID_NAME => {
|
||||||
|
const file_handle: *align(1) std.os.linux.file_handle = @ptrCast(&fid.handle);
|
||||||
|
const file_name_z: [*:0]u8 = @ptrCast((&file_handle.f_handle).ptr + file_handle.handle_bytes);
|
||||||
|
const file_name = std.mem.span(file_name_z);
|
||||||
|
const lfh: Watch.LinuxFileHandle = .{ .handle = file_handle };
|
||||||
|
if (w.handle_table.getPtr(lfh)) |reaction_set| {
|
||||||
|
if (reaction_set.getPtr(file_name)) |step_set| {
|
||||||
|
for (step_set.keys()) |step| {
|
||||||
|
if (step.state != .precheck_done) {
|
||||||
|
step.recursiveReset(gpa);
|
||||||
|
any_dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => |t| std.log.warn("unexpected fanotify event '{s}'", .{@tagName(t)}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn markFailedStepsDirty(gpa: Allocator, all_steps: []const *Step) void {
|
||||||
|
for (all_steps) |step| switch (step.state) {
|
||||||
|
.dependency_failure, .failure, .skipped => step.recursiveReset(gpa),
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
// Now that all dirty steps have been found, the remaining steps that
|
||||||
|
// succeeded from last run shall be marked "cached".
|
||||||
|
for (all_steps) |step| switch (step.state) {
|
||||||
|
.success => step.result_cached = true,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue