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 standard library. Private Function
fnwake(ptr: *constu32, max_waiters: u32) void {
if (max_waiters == 0) return;
constbucket = bucketForAddress(@intFromPtr(ptr));
// To ensure the store to `ptr` is ordered before this check, we effectively want a `.release`// load, but that doesn't exist in the C11 memory model, so emulate it with a non-mutating rmw.if (bucket.num_waiters.fetchAdd(0, .release) == 0) {
@branchHint(.likely);
return; // no waiters
}
// Waiters removed from the linked list under the mutex so we can unpark their threads outside// of the critical section. This forms a singly-linked list of waiters using `Waiter.node.next`.varwaking_head: ?*std.DoublyLinkedList.Node = null;
{
bucket.mutex.lock();
deferbucket.mutex.unlock();
varnum_removed: u32 = 0;
varit = bucket.waiters.first;
while (num_removed < max_waiters) {
constwaiter: *Waiter = @fieldParentPtr("node", itorelsebreak);
it = waiter.node.next;
if (waiter.address != @intFromPtr(ptr)) continue;
constold_status = waiter.thread_status.fetchAnd(
.{ .cancelation = @fromBackingInt(@intCast(0b110)), .awaitable = .all_ones },
.monotonic,
);
switch (old_status.cancelation) {
.parked => {}, // state updated to `.none`
.none => continue, // race with timeout; they are about to lock `bucket.mutex` and remove themselves from the bucket
.canceling => continue, // race with a canceler who hasn't called `removeCanceledWaiter` yet
.canceled => unreachable,
.blocked => unreachable,
.blocked_alertable => unreachable,
.blocked_alertable_canceling => unreachable,
.blocked_canceling => unreachable,
}
// We're waking this waiter. Remove them from the bucket and add them to our local list.bucket.waiters.remove(&waiter.node);
waiter.node.next = waking_head;
waking_head = &waiter.node;
num_removed += 1;
}
_ = bucket.num_waiters.fetchSub(num_removed, .monotonic);
}
varunpark_buf: [128]UnparkTid = undefined;
varunpark_len: usize = 0;
// Finally, unpark the threads.while (waking_head) |node| {
waking_head = node.next;
constwaiter: *Waiter = @fieldParentPtr("node", node);
unpark_buf[unpark_len] = waiter.tid;
if (need_unpark_flag) setUnparkFlag(waiter.unpark_flag);
unpark_len += 1;
if (unpark_len == unpark_buf.len) {
unpark(&unpark_buf, ptr);
unpark_len = 0;
}
}
if (unpark_len > 0) {
unpark(unpark_buf[0..unpark_len], ptr);
}
}