feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.groupAsync
fn groupAsync(
userdata: ?*anyopaque,
type_erased: *Io.Group,
context: []const u8,
context_alignment: Alignment,
start: *const fn (context: *const anyopaque) void,
) void
File
Code
fn groupAsync(
userdata: ?*anyopaque,
type_erased: *Io.Group,
context: []const u8,
context_alignment: Alignment,
start: *const fn (context: *const anyopaque) void,
) void {
const t: *Threaded = @ptrCast(@alignCast(userdata));
const g: Group = .{ .ptr = type_erased };
if (builtin.single_threaded) return groupAsyncEager(start, context.ptr);
const gpa = t.allocator;
const task = Group.Task.create(gpa, g, context, context_alignment, start) catch |err| switch (err) {
error.OutOfMemory => return groupAsyncEager(start, context.ptr),
};
mutexLock(&t.mutex);
const busy_count = t.busy_count;
if (busy_count >= @backingInt(t.async_limit)) {
mutexUnlock(&t.mutex);
task.destroy(gpa);
return groupAsyncEager(start, context.ptr);
}
t.busy_count = busy_count + 1;
const pool_size = t.wait_group.value();
if (pool_size - busy_count == 0) {
t.wait_group.start();
const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch {
t.wait_group.finish();
t.busy_count = busy_count;
mutexUnlock(&t.mutex);
task.destroy(gpa);
return groupAsyncEager(start, context.ptr);
};
thread.detach();
}
// prepend so that the task doesn't finish without observing this and try to decrement the count
// below zero.
_ = g.status().fetchAdd(.{
.num_running = 1,
.have_awaiter = false,
.canceled = false,
}, .monotonic);
t.run_queue.prepend(&task.runnable.node);
mutexUnlock(&t.mutex);
condSignal(&t.cond);
}