feature. See also
. The project being documented here (as the example) is the Zig library itself.
FsEvents.wait
pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error
File
Code
pub fn wait(fse: *FsEvents, maker: *Maker, timeout_ns: ?u64) error{ OutOfMemory, StartFailed }!Watch.WaitResult {
if (fse.watch_roots.len == 0) @panic("nothing to watch");
const gpa = maker.gpa;
const rs = fse.resolved_symbols;
// to occur, because one step modifies a file which is an input to another step. The solution
// to this problem will probably be either:
//
// a) Don't include the output of one step as a watch input of another; only mark external
// files as watch inputs. Or...
//
// b) Note the current event ID when a step begins, and disregard events preceding that ID
// when considering whether to dirty that step in `eventCallback`.
//
// For now, to avoid the redundant rebuilds, we bypass this `since_event` mechanism. This does
// introduce race conditions, but the other `std.Build.Watch` implementations suffer from those
// too at the time of writing, so this is kind of expected.
fse.since_event = .since_now;
const cf_allocator = rs.CFAllocatorCreate(rs.kCFAllocatorUseContext.*, &.{
.version = 0,
.info = @constCast(&gpa),
.retain = null,
.release = null,
.copy_description = null,
.allocate = &cf_alloc_callbacks.allocate,
.reallocate = &cf_alloc_callbacks.reallocate,
.deallocate = &cf_alloc_callbacks.deallocate,
.preferred_size = null,
}) orelse return error.OutOfMemory;
defer rs.CFRelease(cf_allocator);
const cf_paths = try gpa.alloc(?CFStringRef, fse.watch_roots.len);
@memset(cf_paths, null);
defer {
for (cf_paths) |o| if (o) |p| rs.CFRelease(p);
gpa.free(cf_paths);
}
for (fse.watch_roots, cf_paths) |raw_path, *cf_path| {
cf_path.* = rs.CFStringCreateWithCString(cf_allocator, raw_path, .utf8);
}
const cf_paths_array = rs.CFArrayCreate(cf_allocator, @ptrCast(cf_paths), @intCast(cf_paths.len), null);
defer rs.CFRelease(cf_paths_array);
const callback_ctx: EventCallbackCtx = .{
.fse = fse,
.maker = maker,
};
const event_stream = rs.FSEventStreamCreate(
null,
&eventCallback,
&.{
.version = 0,
.info = @constCast(&callback_ctx),
.retain = null,
.release = null,
.copy_description = null,
},
cf_paths_array,
fse.since_event,
0.05,
.{ .watch_root = true, .file_events = true },
);
defer rs.FSEventStreamRelease(event_stream);
rs.FSEventStreamSetDispatchQueue(event_stream, fse.dispatch_queue);
defer rs.FSEventStreamInvalidate(event_stream);
if (!rs.FSEventStreamStart(event_stream)) return error.StartFailed;
defer rs.FSEventStreamStop(event_stream);
const result = fse.waiting_semaphore.wait(timeout: {
const ns = timeout_ns orelse break :timeout .FOREVER;
break :timeout .time(.NOW, @intCast(ns));
});
return switch (result) {
0 => .dirty,
else => .timeout,
};
}