io_interface: First mock of the Group-related methods

This commit is contained in:
2026-06-04 13:38:35 +02:00
parent ce51e82363
commit 3bdcce3ade
+123 -12
View File
@@ -22,6 +22,7 @@ const Duration = Io.Duration;
const RandomSecureError = Io.RandomSecureError; const RandomSecureError = Io.RandomSecureError;
const Queue = Io.Queue; const Queue = Io.Queue;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const TaskID = Node.TaskID;
pub fn buildIOInterfaceForNode(node: *Node) Io { pub fn buildIOInterfaceForNode(node: *Node) Io {
return .{ return .{
@@ -218,6 +219,78 @@ fn cancel(
@panic("Not implemented yet"); @panic("Not implemented yet");
} }
const TaskContext = struct {
context_alignment: std.mem.Alignment,
alloc_len: usize,
fn ptr(self: *TaskContext) [*]u8 {
const base: [*]u8 = @ptrCast(self);
const offset = self.context_alignment.forward(@intFromPtr(base) + @sizeOf(TaskContext)) - @intFromPtr(base);
return base + offset;
}
fn alloc(self: *TaskContext) []align(@alignOf(TaskContext)) u8 {
const base: [*]align(@alignOf(TaskContext)) u8 = @ptrCast(self);
return base[0..self.alloc_len];
}
};
const TaskGroup = struct {
gpa: Allocator,
ids: std.ArrayList(TaskID) = .empty,
contexts: std.ArrayList(*TaskContext) = .empty,
fn init(gpa: Allocator) TaskGroup {
return .{
.gpa = gpa,
};
}
fn add(self: *TaskGroup, id: TaskID, context: *TaskContext) !void {
try self.ids.append(self.gpa, id);
errdefer _ = self.ids.pop();
try self.contexts.append(self.gpa, context);
}
fn remove(self: *TaskGroup, id: TaskID) void {
var found: ?usize = null;
for (self.ids.items, 0..) |current_id, i| {
if (current_id == id) {
found = i;
break;
}
}
if (found) |i| {
const context = self.contexts.items[i];
self.gpa.free(context.alloc());
_ = self.ids.orderedRemove(i);
_ = self.contexts.orderedRemove(i);
}
}
fn deinit(self: *TaskGroup) void {
for (self.contexts.items) |context| {
self.gpa.free(context.alloc());
}
self.contexts.deinit(self.gpa);
self.ids.deinit(self.gpa);
}
};
fn getOrCreatePendingTaskGroup(gpa: Allocator, type_erased: *Group) !*TaskGroup {
const token = type_erased.token.load(.acquire);
if (token) |ptr| return @ptrCast(@alignCast(ptr));
const group = try gpa.create(TaskGroup);
errdefer gpa.destroy(group);
group.* = .init(gpa);
type_erased.token.store(@ptrCast(group), .release);
type_erased.state = 0;
return group;
}
fn groupAsync( fn groupAsync(
userdata: ?*anyopaque, userdata: ?*anyopaque,
type_erased: *Group, type_erased: *Group,
@@ -225,10 +298,41 @@ fn groupAsync(
context_alignment: std.mem.Alignment, context_alignment: std.mem.Alignment,
start: *const fn (context: *const anyopaque) void, start: *const fn (context: *const anyopaque) void,
) void { ) void {
_ = userdata; const node: *Node = @ptrCast(@alignCast(userdata.?));
_ = type_erased;
_ = context_alignment; const group = getOrCreatePendingTaskGroup(node.gpa, type_erased) catch {
start(context.ptr); start(context.ptr);
return;
};
const max_context_misalignment = context_alignment.toByteUnits() -| @alignOf(TaskContext);
const worst_case_context_offset = context_alignment.forward(@sizeOf(TaskContext) + max_context_misalignment);
const alloc_len = worst_case_context_offset + context.len;
const alloc = node.gpa.alignedAlloc(u8, .of(TaskContext), alloc_len) catch {
start(context.ptr);
return;
};
const task_context: *TaskContext = @ptrCast(@alignCast(alloc.ptr));
task_context.* = .{
.context_alignment = context_alignment,
.alloc_len = alloc_len,
};
@memcpy(task_context.ptr()[0..context.len], context);
const id = node.spawn(start, task_context.ptr()) catch {
node.gpa.free(task_context.alloc());
start(context.ptr);
return;
};
group.add(id, task_context) catch {
node.despawn(id);
node.gpa.free(task_context.alloc());
start(context.ptr);
return;
};
} }
fn groupConcurrent( fn groupConcurrent(
@@ -243,21 +347,28 @@ fn groupConcurrent(
_ = context; _ = context;
_ = context_alignment; _ = context_alignment;
_ = start; _ = start;
@panic("Not implemented yet"); @panic("Not implemented yet\n");
} }
fn groupAwait(userdata: ?*anyopaque, type_erased: *Group, initial_token: *anyopaque) Cancelable!void { fn groupAwait(userdata: ?*anyopaque, type_erased: *Group, initial_token: *anyopaque) Cancelable!void {
_ = userdata; const node: *Node = @ptrCast(@alignCast(userdata.?));
_ = type_erased; const group: *TaskGroup = @ptrCast(@alignCast(initial_token));
_ = initial_token; defer {
@panic("Not implemented yet"); group.deinit();
node.gpa.destroy(group);
type_erased.token.store(null, .release);
type_erased.state = 0;
}
while (group.ids.items.len > 0) {
const id = node.wait(group.ids.items) catch @panic("TODO");
group.remove(id);
node.despawn(id);
}
} }
fn groupCancel(userdata: ?*anyopaque, type_erased: *Group, initial_token: *anyopaque) void { fn groupCancel(userdata: ?*anyopaque, type_erased: *Group, initial_token: *anyopaque) void {
_ = userdata; groupAwait(userdata, type_erased, initial_token) catch {};
_ = type_erased;
_ = initial_token;
@panic("Not implemented yet");
} }
fn recancel(userdata: ?*anyopaque) void { fn recancel(userdata: ?*anyopaque) void {