feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.await
fn await(
userdata: ?*anyopaque,
any_future: *Io.AnyFuture,
result: []u8,
result_alignment: Alignment,
) void
File
Code
fn await(
userdata: ?*anyopaque,
any_future: *Io.AnyFuture,
result: []u8,
result_alignment: Alignment,
) void {
_ = result_alignment;
if (builtin.single_threaded) unreachable;
const t: *Threaded = @ptrCast(@alignCast(userdata));
const future: *Future = @ptrCast(@alignCast(any_future));
var num_completed: std.atomic.Value(u32) = .init(0);
future.awaiter = &num_completed;
const pre_await_status = future.status.fetchOr(.{
.tag = .pending_awaited,
.thread = .null,
}, .acq_rel);
switch (pre_await_status.tag) {
.pending => while (Thread.futexWait(&num_completed.raw, 0, null)) {
switch (num_completed.load(.acquire)) {
0 => continue,
1 => break,
else => unreachable,
}
} else |err| switch (err) {
error.Canceled => {
const pre_cancel_status = future.status.fetchOr(.{
.tag = .pending_canceled,
.thread = .null,
}, .acq_rel);
const done_status = switch (pre_cancel_status.tag) {
.pending => unreachable,
.pending_awaited => done_status: {
const working_thread = pre_cancel_status.thread.unpack();
future.waitForCancelWithSignaling(t, &num_completed, @alignCast(working_thread));
break :done_status future.status.load(.monotonic);
},
.pending_canceled => unreachable,
.done => done_status: {
// task thread already figured out that they need to update `future.awaiter`.
future.waitForCancelWithSignaling(t, &num_completed, null);
// not actually a problem for the logic below.
break :done_status pre_cancel_status;
},
};
// for us. Because `done_status.tag == .done`, the information about whether there
// was an acknowledged cancelation is encoded in `done_status.thread`.
assert(done_status.tag == .done);
switch (done_status.thread) {
.null => recancelInner(),
.all_ones => {},
_ => unreachable,
}
},
},
.pending_awaited => unreachable,
.pending_canceled => unreachable,
.done => {},
}
@memcpy(result, future.resultPointer());
future.destroy(t.allocator);
}