authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-22 13:21:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
log41070932f8a3a1dead7fb424f427b04824c19c72
tree3005b6e1f203c0ccdc39a7c8ef3e997c33bfe8dd
parentdf84dc18bc2fa18770591be4d1e0cabc8d4b28c2

revert adding asyncDetached

instead we will have Io.Group

1 files changed, 10 insertions(+), 104 deletions(-)

lib/std/Io/IoUring.zig+10-104
......@@ -10,12 +10,9 @@ const IoUring = std.os.linux.IoUring;
1010
1111/// Must be a thread-safe allocator.
1212gpa: Allocator,
13mutex: std.Thread.Mutex,
1314main_fiber_buffer: [@sizeOf(Fiber) + Fiber.max_result_size]u8 align(@alignOf(Fiber)),
1415threads: Thread.List,
15detached: struct {
16 mutex: std.Io.Mutex,
17 list: std.DoublyLinkedList,
18},
1916
2017/// Empirically saw >128KB being used by the self-hosted backend to panic.
2118const idle_stack_size = 256 * 1024;
......@@ -142,7 +139,6 @@ pub fn io(el: *EventLoop) Io {
142139 .async = async,
143140 .concurrent = concurrent,
144141 .await = await,
145 .asyncDetached = asyncDetached,
146142 .select = select,
147143 .cancel = cancel,
148144 .cancelRequested = cancelRequested,
......@@ -172,16 +168,13 @@ pub fn init(el: *EventLoop, gpa: Allocator) !void {
172168 errdefer gpa.free(allocated_slice);
173169 el.* = .{
174170 .gpa = gpa,
171 .mutex = .{},
175172 .main_fiber_buffer = undefined,
176173 .threads = .{
177174 .allocated = @ptrCast(allocated_slice[0..threads_size]),
178175 .reserved = 1,
179176 .active = 1,
180177 },
181 .detached = .{
182 .mutex = .init,
183 .list = .{},
184 },
185178 };
186179 const main_fiber: *Fiber = @ptrCast(&el.main_fiber_buffer);
187180 main_fiber.* = .{
......@@ -223,22 +216,6 @@ pub fn init(el: *EventLoop, gpa: Allocator) !void {
223216}
224217
225218pub fn deinit(el: *EventLoop) void {
226 while (true) cancel(el, detached_future: {
227 el.detached.mutex.lock(el.io()) catch |err| switch (err) {
228 error.Canceled => unreachable, // main fiber cannot be canceled
229 };
230 defer el.detached.mutex.unlock(el.io());
231 const detached: *DetachedClosure = @fieldParentPtr(
232 "detached_queue_node",
233 el.detached.list.pop() orelse break,
234 );
235 // notify the detached fiber that it is no longer allowed to recycle itself
236 detached.detached_queue_node = .{
237 .prev = &detached.detached_queue_node,
238 .next = &detached.detached_queue_node,
239 };
240 break :detached_future @ptrCast(detached.fiber);
241 }, &.{}, .@"1");
242219 const active_threads = @atomicLoad(u32, &el.threads.active, .acquire);
243220 for (el.threads.allocated[0..active_threads]) |*thread| {
244221 const ready_fiber = @atomicLoad(?*Fiber, &thread.ready_queue, .monotonic);
......@@ -492,7 +469,7 @@ const SwitchMessage = struct {
492469 const PendingTask = union(enum) {
493470 nothing,
494471 reschedule,
495 recycle,
472 recycle: *Fiber,
496473 register_awaiter: *?*Fiber,
497474 register_select: []const *Io.AnyFuture,
498475 mutex_lock: struct {
......@@ -516,10 +493,8 @@ const SwitchMessage = struct {
516493 assert(prev_fiber.queue_next == null);
517494 el.schedule(thread, .{ .head = prev_fiber, .tail = prev_fiber });
518495 },
519 .recycle => {
520 const prev_fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.prev));
521 assert(prev_fiber.queue_next == null);
522 el.recycle(prev_fiber);
496 .recycle => |fiber| {
497 el.recycle(fiber);
523498 },
524499 .register_awaiter => |awaiter| {
525500 const prev_fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.prev));
......@@ -829,12 +804,9 @@ fn fiberEntry() callconv(.naked) void {
829804 switch (builtin.cpu.arch) {
830805 .x86_64 => asm volatile (
831806 \\ leaq 8(%%rsp), %%rdi
832 \\ jmpq *(%%rsp)
833 ),
834 .aarch64 => asm volatile (
835 \\ mov x0, sp
836 \\ ldr x2, [sp, #-8]
837 \\ br x2
807 \\ jmp %[AsyncClosure_call:P]
808 :
809 : [AsyncClosure_call] "X" (&AsyncClosure.call),
838810 ),
839811 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
840812 }
......@@ -905,18 +877,16 @@ fn concurrent(
905877 std.log.debug("allocated {*}", .{fiber});
906878
907879 const closure: *AsyncClosure = .fromFiber(fiber);
908 const stack_end: [*]align(16) usize = @ptrCast(@alignCast(closure));
909 (stack_end - 1)[0..1].* = .{@intFromPtr(&AsyncClosure.call)};
910880 fiber.* = .{
911881 .required_align = {},
912882 .context = switch (builtin.cpu.arch) {
913883 .x86_64 => .{
914 .rsp = @intFromPtr(stack_end - 1),
884 .rsp = @intFromPtr(closure) - @sizeOf(usize),
915885 .rbp = 0,
916886 .rip = @intFromPtr(&fiberEntry),
917887 },
918888 .aarch64 => .{
919 .sp = @intFromPtr(stack_end),
889 .sp = @intFromPtr(closure) - @sizeOf(usize) - 1,
920890 .fp = 0,
921891 .pc = @intFromPtr(&fiberEntry),
922892 },
......@@ -968,70 +938,6 @@ const DetachedClosure = struct {
968938 }
969939};
970940
971fn asyncDetached(
972 userdata: ?*anyopaque,
973 context: []const u8,
974 context_alignment: std.mem.Alignment,
975 start: *const fn (context: *const anyopaque) void,
976) void {
977 assert(context_alignment.compare(.lte, Fiber.max_context_align)); // TODO
978 assert(context.len <= Fiber.max_context_size); // TODO
979
980 const event_loop: *EventLoop = @ptrCast(@alignCast(userdata));
981 const fiber = Fiber.allocate(event_loop) catch {
982 start(context.ptr);
983 return;
984 };
985 std.log.debug("allocated {*}", .{fiber});
986
987 const current_thread: *Thread = .current();
988 const closure: *DetachedClosure = @ptrFromInt(Fiber.max_context_align.max(.of(DetachedClosure)).backward(
989 @intFromPtr(fiber.allocatedEnd()) - Fiber.max_context_size,
990 ) - @sizeOf(DetachedClosure));
991 const stack_end: [*]align(16) usize = @ptrCast(@alignCast(closure));
992 (stack_end - 1)[0..1].* = .{@intFromPtr(&DetachedClosure.call)};
993 fiber.* = .{
994 .required_align = {},
995 .context = switch (builtin.cpu.arch) {
996 .x86_64 => .{
997 .rsp = @intFromPtr(stack_end - 1),
998 .rbp = 0,
999 .rip = @intFromPtr(&fiberEntry),
1000 },
1001 .aarch64 => .{
1002 .sp = @intFromPtr(stack_end),
1003 .fp = 0,
1004 .pc = @intFromPtr(&fiberEntry),
1005 },
1006 else => |arch| @compileError("unimplemented architecture: " ++ @tagName(arch)),
1007 },
1008 .awaiter = null,
1009 .queue_next = null,
1010 .cancel_thread = null,
1011 .awaiting_completions = .initEmpty(),
1012 };
1013 closure.* = .{
1014 .event_loop = event_loop,
1015 .fiber = fiber,
1016 .start = start,
1017 .detached_queue_node = .{},
1018 };
1019 {
1020 event_loop.detached.mutex.lock(event_loop.io()) catch |err| switch (err) {
1021 error.Canceled => {
1022 event_loop.recycle(fiber);
1023 start(context.ptr);
1024 return;
1025 },
1026 };
1027 defer event_loop.detached.mutex.unlock(event_loop.io());
1028 event_loop.detached.list.append(&closure.detached_queue_node);
1029 }
1030 @memcpy(closure.contextPointer(), context);
1031
1032 event_loop.schedule(current_thread, .{ .head = fiber, .tail = fiber });
1033}
1034
1035941fn await(
1036942 userdata: ?*anyopaque,
1037943 any_future: *std.Io.AnyFuture,