authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-03-31 23:51:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-02 16:30:59-07:00
log5c4ddb8d3593fd2d0aa2b65c66d6710ed8f6113b
tree453fc35fff11241a64a3545cd1f553b8041f9b7a
parentc8950b5dd549ffe2ead1979528e33c7a94540b8c

EventLoop: let the allocator do its job

to bucket and free fiber allocations

1 files changed, 8 insertions(+), 25 deletions(-)

lib/std/Io/EventLoop.zig+8-25
...@@ -26,7 +26,6 @@ const Thread = struct {...@@ -26,7 +26,6 @@ const Thread = struct {
26 idle_context: Context,26 idle_context: Context,
27 current_context: *Context,27 current_context: *Context,
28 ready_queue: ?*Fiber,28 ready_queue: ?*Fiber,
29 free_queue: ?*Fiber,
30 io_uring: IoUring,29 io_uring: IoUring,
31 idle_search_index: u32,30 idle_search_index: u32,
32 steal_ready_search_index: u32,31 steal_ready_search_index: u32,
...@@ -78,12 +77,6 @@ const Fiber = struct {...@@ -78,12 +77,6 @@ const Fiber = struct {
78 );77 );
7978
80 fn allocate(el: *EventLoop) error{OutOfMemory}!*Fiber {79 fn allocate(el: *EventLoop) error{OutOfMemory}!*Fiber {
81 const thread: *Thread = .current();
82 if (thread.free_queue) |free_fiber| {
83 thread.free_queue = free_fiber.queue_next;
84 free_fiber.queue_next = null;
85 return free_fiber;
86 }
87 return @ptrCast(try el.gpa.alignedAlloc(u8, @alignOf(Fiber), allocation_size));80 return @ptrCast(try el.gpa.alignedAlloc(u8, @alignOf(Fiber), allocation_size));
88 }81 }
8982
...@@ -129,18 +122,15 @@ const Fiber = struct {...@@ -129,18 +122,15 @@ const Fiber = struct {
129 )) |cancel_thread| assert(cancel_thread == Thread.canceling);122 )) |cancel_thread| assert(cancel_thread == Thread.canceling);
130 }123 }
131124
132 fn recycle(fiber: *Fiber) void {
133 const thread: *Thread = .current();
134 std.log.debug("recyling {*}", .{fiber});
135 assert(fiber.queue_next == null);
136 //@memset(fiber.allocatedSlice(), undefined); // (race)
137 fiber.queue_next = thread.free_queue;
138 thread.free_queue = fiber;
139 }
140
141 const Queue = struct { head: *Fiber, tail: *Fiber };125 const Queue = struct { head: *Fiber, tail: *Fiber };
142};126};
143127
128fn recycle(el: *EventLoop, fiber: *Fiber) void {
129 std.log.debug("recyling {*}", .{fiber});
130 assert(fiber.queue_next == null);
131 el.gpa.free(fiber.allocatedSlice());
132}
133
144pub fn io(el: *EventLoop) Io {134pub fn io(el: *EventLoop) Io {
145 return .{135 return .{
146 .userdata = el,136 .userdata = el,
...@@ -207,7 +197,6 @@ pub fn init(el: *EventLoop, gpa: Allocator) !void {...@@ -207,7 +197,6 @@ pub fn init(el: *EventLoop, gpa: Allocator) !void {
207 },197 },
208 .current_context = &main_fiber.context,198 .current_context = &main_fiber.context,
209 .ready_queue = null,199 .ready_queue = null,
210 .free_queue = null,
211 .io_uring = try IoUring.init(io_uring_entries, 0),200 .io_uring = try IoUring.init(io_uring_entries, 0),
212 .idle_search_index = 1,201 .idle_search_index = 1,
213 .steal_ready_search_index = 1,202 .steal_ready_search_index = 1,
...@@ -227,11 +216,6 @@ pub fn deinit(el: *EventLoop) void {...@@ -227,11 +216,6 @@ pub fn deinit(el: *EventLoop) void {
227 const allocated_ptr: [*]align(@alignOf(Thread)) u8 = @alignCast(@ptrCast(el.threads.allocated.ptr));216 const allocated_ptr: [*]align(@alignOf(Thread)) u8 = @alignCast(@ptrCast(el.threads.allocated.ptr));
228 const idle_stack_end_offset = std.mem.alignForward(usize, el.threads.allocated.len * @sizeOf(Thread) + idle_stack_size, std.heap.page_size_max);217 const idle_stack_end_offset = std.mem.alignForward(usize, el.threads.allocated.len * @sizeOf(Thread) + idle_stack_size, std.heap.page_size_max);
229 for (el.threads.allocated[1..active_threads]) |*thread| thread.thread.join();218 for (el.threads.allocated[1..active_threads]) |*thread| thread.thread.join();
230 for (el.threads.allocated[0..active_threads]) |*thread| while (thread.free_queue) |free_fiber| {
231 thread.free_queue = free_fiber.queue_next;
232 free_fiber.queue_next = null;
233 el.gpa.free(free_fiber.allocatedSlice());
234 };
235 el.gpa.free(allocated_ptr[0..idle_stack_end_offset]);219 el.gpa.free(allocated_ptr[0..idle_stack_end_offset]);
236 el.* = undefined;220 el.* = undefined;
237}221}
...@@ -343,7 +327,6 @@ fn schedule(el: *EventLoop, thread: *Thread, ready_queue: Fiber.Queue) void {...@@ -343,7 +327,6 @@ fn schedule(el: *EventLoop, thread: *Thread, ready_queue: Fiber.Queue) void {
343 .idle_context = undefined,327 .idle_context = undefined,
344 .current_context = &new_thread.idle_context,328 .current_context = &new_thread.idle_context,
345 .ready_queue = ready_queue.head,329 .ready_queue = ready_queue.head,
346 .free_queue = null,
347 .io_uring = IoUring.init(io_uring_entries, 0) catch |err| {330 .io_uring = IoUring.init(io_uring_entries, 0) catch |err| {
348 @atomicStore(u32, &el.threads.reserved, new_thread_index, .release);331 @atomicStore(u32, &el.threads.reserved, new_thread_index, .release);
349 // no more access to `thread` after giving up reservation332 // no more access to `thread` after giving up reservation
...@@ -501,7 +484,7 @@ const SwitchMessage = struct {...@@ -501,7 +484,7 @@ const SwitchMessage = struct {
501 el.schedule(thread, .{ .head = prev_fiber, .tail = prev_fiber });484 el.schedule(thread, .{ .head = prev_fiber, .tail = prev_fiber });
502 },485 },
503 .recycle => |fiber| {486 .recycle => |fiber| {
504 fiber.recycle();487 el.recycle(fiber);
505 },488 },
506 .register_awaiter => |awaiter| {489 .register_awaiter => |awaiter| {
507 const prev_fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.prev));490 const prev_fiber: *Fiber = @alignCast(@fieldParentPtr("context", message.contexts.prev));
...@@ -795,7 +778,7 @@ fn @"await"(...@@ -795,7 +778,7 @@ fn @"await"(
795 if (@atomicLoad(?*Fiber, &future_fiber.awaiter, .acquire) != Fiber.finished)778 if (@atomicLoad(?*Fiber, &future_fiber.awaiter, .acquire) != Fiber.finished)
796 event_loop.yield(null, .{ .register_awaiter = &future_fiber.awaiter });779 event_loop.yield(null, .{ .register_awaiter = &future_fiber.awaiter });
797 @memcpy(result, future_fiber.resultBytes(result_alignment));780 @memcpy(result, future_fiber.resultBytes(result_alignment));
798 future_fiber.recycle();781 event_loop.recycle(future_fiber);
799}782}
800783
801fn cancel(784fn cancel(