feature. See also
. The project being documented here (as the example) is the Zig library itself.
Kqueue.schedule
fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void
File
Code
fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {
{
var fiber = ready_queue.head;
while (true) {
std.log.debug("scheduling {*}", .{fiber});
fiber = fiber.queue_next orelse break;
}
assert(fiber == ready_queue.tail);
}
const new_thread_index = @atomicLoad(u32, &k.threads.active, .acquire);
for (0..@min(max_idle_search, new_thread_index)) |_| {
defer thread.idle_search_index += 1;
if (thread.idle_search_index == new_thread_index) thread.idle_search_index = 0;
const idle_search_thread = &k.threads.allocated[0..new_thread_index][thread.idle_search_index];
if (idle_search_thread == thread) continue;
if (@cmpxchgWeak(
?*Fiber,
&idle_search_thread.ready_queue,
null,
ready_queue.head,
.release,
.monotonic,
)) |_| continue;
const changes = [_]posix.Kevent{
.{
.ident = 0,
.filter = std.c.EVFILT.USER,
.flags = std.c.EV.ADD | std.c.EV.ONESHOT,
.fflags = std.c.NOTE.TRIGGER,
.data = 0,
.udata = @backingInt(Completion.UserData.wakeup),
},
};
_ = kevent(idle_search_thread.kq_fd, &changes, &.{}, null) catch |err| {
@panic(@errorName(err));
};
return;
}
spawn_thread: {
if (new_thread_index == k.threads.allocated.len or @cmpxchgWeak(
u32,
&k.threads.reserved,
new_thread_index,
new_thread_index + 1,
.acquire,
.monotonic,
) != null) break :spawn_thread;
const new_thread = &k.threads.allocated[new_thread_index];
const next_thread_index = new_thread_index + 1;
new_thread.* = .{
.thread = undefined,
.idle_context = undefined,
.current_context = &new_thread.idle_context,
.ready_queue = ready_queue.head,
.kq_fd = createFileDescriptor() catch |err| {
@atomicStore(u32, &k.threads.reserved, new_thread_index, .release);
std.log.warn("unable to create worker thread due to kqueue init failure: {t}", .{err});
break :spawn_thread;
},
.idle_search_index = 0,
.steal_ready_search_index = 0,
.wait_queues = .empty,
};
new_thread.thread = std.Thread.spawn(.{
.stack_size = idle_stack_size,
.allocator = k.gpa,
}, threadEntry, .{ k, new_thread_index }) catch |err| {
closeFd(new_thread.kq_fd);
@atomicStore(u32, &k.threads.reserved, new_thread_index, .release);
std.log.warn("unable to create worker thread due spawn failure: {s}", .{@errorName(err)});
break :spawn_thread;
};
@atomicStore(u32, &k.threads.active, next_thread_index, .release);
return;
}
while (@cmpxchgWeak(
?*Fiber,
&thread.ready_queue,
ready_queue.tail.queue_next,
ready_queue.head,
.acq_rel,
.acquire,
)) |old_head| ready_queue.tail.queue_next = old_head;
}