Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

wait

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;

    // At the time of writing, using `since_event` in the obvious way causes redundant rebuilds
    // 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, // 0.05s latency; higher values increase efficiency by coalescing more events
        .{ .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,
    };
}