commit cb7d76930d24502ddd809028be54fdb6447b971c
parent 9a630c179e45cbf574f3613efce2f5d0c507031b
Author: Sylvia Ivory <git@sivory.net>
Date: Sat, 24 Jan 2026 23:33:48 -0800
Use std.DoublyLinkedList for Scheduler
Diffstat:
| M | src/scheduler.zig | | | 62 | ++++++++++++++++++++++++++++++-------------------------------- |
1 file changed, 30 insertions(+), 32 deletions(-)
diff --git a/src/scheduler.zig b/src/scheduler.zig
@@ -3,16 +3,14 @@ const std = @import("std");
const Self = @This();
tid_counter: usize,
-tasks_head: ?*Task,
-tasks_tail: ?*Task,
+tasks: std.DoublyLinkedList,
scheduler_task: *Task,
allocator: std.mem.Allocator,
pub const Task = struct {
tid: usize,
- next: ?*Task,
+ node: std.DoublyLinkedList.Node,
- // TODO; make generic(?)
func: *const fn (*Self, ?*anyopaque) callconv(.c) void,
arg: ?*anyopaque,
@@ -27,7 +25,7 @@ pub const Task = struct {
};
pub fn new(gpa: std.mem.Allocator) Self {
- return .{ .tid_counter = 1, .tasks_head = null, .tasks_tail = null, .scheduler_task = undefined, .allocator = gpa };
+ return .{ .tid_counter = 1, .tasks = .{}, .scheduler_task = undefined, .allocator = gpa };
}
fn push_stack(sp: *usize, value: usize) *usize {
@@ -44,7 +42,6 @@ pub fn fork(self: *Self, f: *const fn (*Self, ?*anyopaque) callconv(.c) void, ar
task.func = f;
task.arg = arg;
- task.next = null;
const stack_top = @intFromPtr(&task.stack) + task.stack.len;
var sp: *usize = @ptrFromInt(stack_top);
@@ -62,18 +59,15 @@ pub fn fork(self: *Self, f: *const fn (*Self, ?*anyopaque) callconv(.c) void, ar
task.saved_sp = sp;
- if (self.tasks_tail) |tail| {
- tail.next = task;
- }
- self.tasks_tail = task;
+ self.tasks.append(&task.node);
+}
- if (self.tasks_head == null) {
- self.tasks_head = task;
- }
+fn get_current(self: *Self) *Task {
+ return @alignCast(@fieldParentPtr("node", self.tasks.first.?));
}
pub fn join(self: *Self) !void {
- if (self.tasks_head == null) {
+ if (self.tasks.first == null) {
// Nothing to do
return;
}
@@ -82,40 +76,44 @@ pub fn join(self: *Self) !void {
self.scheduler_task.tid = 0;
self.scheduler_task.saved_sp = @ptrFromInt(@frameAddress());
- context_switch(&self.scheduler_task.saved_sp, self.tasks_head.?.saved_sp);
+ context_switch(&self.scheduler_task.saved_sp, self.get_current().saved_sp);
}
pub fn yield(self: *Self) void {
- if (self.tasks_head == self.tasks_tail) {
+ // Single task
+ if (self.tasks.first == self.tasks.last) {
return;
}
- const current = self.tasks_head.?;
- self.tasks_head = current.next;
- current.next = null;
- self.tasks_tail.?.next = current;
- self.tasks_tail = current;
-
- const next = self.tasks_head.?;
+ const node = self.tasks.popFirst().?;
+ self.tasks.append(node);
+ const current: *Task = @alignCast(@fieldParentPtr("node", node));
- context_switch(¤t.saved_sp, next.saved_sp);
+ context_switch(¤t.saved_sp, self.get_current().saved_sp);
}
pub fn get_tid(self: *Self) usize {
- return self.tasks_head.?.tid;
+ return self.get_current().tid;
}
export fn trampoline_inner(self: *Self) callconv(.c) void {
- const current = self.tasks_head.?;
- current.func(self, current.arg);
+ {
+ const current: *Task = self.get_current();
+ current.func(self, current.arg);
+ }
+
+ // We aren't preserving sp as the function ended
+ const current: *Task = @alignCast(@fieldParentPtr("node", self.tasks.popFirst().?));
+ var saved_sp = current.saved_sp;
+ // Free the task
+ self.allocator.destroy(current);
- if (current.next) |next| {
- self.tasks_head = next;
+ if (self.tasks.first) |node| {
+ const next: *Task = @alignCast(@fieldParentPtr("node", node));
+ context_switch(&saved_sp, next.saved_sp);
} else {
- self.tasks_head = self.scheduler_task;
+ context_switch(&saved_sp, self.scheduler_task.saved_sp);
}
-
- context_switch(¤t.saved_sp, self.tasks_head.?.saved_sp);
}
comptime {