authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-23 05:24:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:51-07:00
log6a64c9b7c8971486a818d8cb2ae44bb4dab4497f
tree5687d7e23a65d0c8164b6a2c4c6be6885d3135ee
parentcc11dd1f87d0e16e9af4d80b28dbe2f0d1a7e3b2

std.Io.Kqueue: add missing Thread deinit logic


1 files changed, 30 insertions(+), 3 deletions(-)

lib/std/Io/Kqueue.zig+30-3
...@@ -36,6 +36,14 @@ const Thread = struct {...@@ -36,6 +36,14 @@ const Thread = struct {
36 kq_fd: posix.fd_t,36 kq_fd: posix.fd_t,
37 idle_search_index: u32,37 idle_search_index: u32,
38 steal_ready_search_index: u32,38 steal_ready_search_index: u32,
39 /// For ensuring multiple fibers waiting on the same file descriptor and
40 /// filter use the same kevent.
41 wait_queues: std.AutoArrayHashMapUnmanaged(WaitQueueKey, *Fiber),
42
43 const WaitQueueKey = struct {
44 ident: usize,
45 filter: i32,
46 };
3947
40 const canceling: ?*Thread = @ptrFromInt(@alignOf(Thread));48 const canceling: ?*Thread = @ptrFromInt(@alignOf(Thread));
4149
...@@ -54,6 +62,13 @@ const Thread = struct {...@@ -54,6 +62,13 @@ const Thread = struct {
54 reserved: u32,62 reserved: u32,
55 active: u32,63 active: u32,
56 };64 };
65
66 fn deinit(thread: *Thread, gpa: Allocator) void {
67 posix.close(thread.kq_fd);
68 assert(thread.wait_queues.count() == 0);
69 thread.wait_queues.deinit(gpa);
70 thread.* = undefined;
71 }
57};72};
5873
59const Fiber = struct {74const Fiber = struct {
...@@ -138,8 +153,14 @@ fn recycle(k: *Kqueue, fiber: *Fiber) void {...@@ -138,8 +153,14 @@ fn recycle(k: *Kqueue, fiber: *Fiber) void {
138 k.gpa.free(fiber.allocatedSlice());153 k.gpa.free(fiber.allocatedSlice());
139}154}
140155
141pub fn init(k: *Kqueue, gpa: Allocator) !void {156pub const InitOptions = struct {
142 const threads_size = @max(std.Thread.getCpuCount() catch 1, 1) * @sizeOf(Thread);157 n_threads: ?usize = null,
158};
159
160pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void {
161 assert(options.n_threads != 0);
162 const n_threads = @max(1, options.n_threads orelse std.Thread.getCpuCount() catch 1);
163 const threads_size = n_threads * @sizeOf(Thread);
143 const idle_stack_end_offset = std.mem.alignForward(usize, threads_size + idle_stack_size, std.heap.page_size_max);164 const idle_stack_end_offset = std.mem.alignForward(usize, threads_size + idle_stack_size, std.heap.page_size_max);
144 const allocated_slice = try gpa.alignedAlloc(u8, .of(Thread), idle_stack_end_offset);165 const allocated_slice = try gpa.alignedAlloc(u8, .of(Thread), idle_stack_end_offset);
145 errdefer gpa.free(allocated_slice);166 errdefer gpa.free(allocated_slice);
...@@ -186,6 +207,7 @@ pub fn init(k: *Kqueue, gpa: Allocator) !void {...@@ -186,6 +207,7 @@ pub fn init(k: *Kqueue, gpa: Allocator) !void {
186 .kq_fd = try posix.kqueue(),207 .kq_fd = try posix.kqueue(),
187 .idle_search_index = 1,208 .idle_search_index = 1,
188 .steal_ready_search_index = 1,209 .steal_ready_search_index = 1,
210 .wait_queues = .empty,
189 };211 };
190 errdefer std.posix.close(main_thread.kq_fd);212 errdefer std.posix.close(main_thread.kq_fd);
191 std.log.debug("created main idle {*}", .{&main_thread.idle_context});213 std.log.debug("created main idle {*}", .{&main_thread.idle_context});
...@@ -199,10 +221,13 @@ pub fn deinit(k: *Kqueue) void {...@@ -199,10 +221,13 @@ pub fn deinit(k: *Kqueue) void {
199 assert(ready_fiber == null or ready_fiber == Fiber.finished); // pending async221 assert(ready_fiber == null or ready_fiber == Fiber.finished); // pending async
200 }222 }
201 k.yield(null, .exit);223 k.yield(null, .exit);
224 const main_thread = &k.threads.allocated[0];
225 const gpa = k.gpa;
226 main_thread.deinit(gpa);
202 const allocated_ptr: [*]align(@alignOf(Thread)) u8 = @ptrCast(@alignCast(k.threads.allocated.ptr));227 const allocated_ptr: [*]align(@alignOf(Thread)) u8 = @ptrCast(@alignCast(k.threads.allocated.ptr));
203 const idle_stack_end_offset = std.mem.alignForward(usize, k.threads.allocated.len * @sizeOf(Thread) + idle_stack_size, std.heap.page_size_max);228 const idle_stack_end_offset = std.mem.alignForward(usize, k.threads.allocated.len * @sizeOf(Thread) + idle_stack_size, std.heap.page_size_max);
204 for (k.threads.allocated[1..active_threads]) |*thread| thread.thread.join();229 for (k.threads.allocated[1..active_threads]) |*thread| thread.thread.join();
205 k.gpa.free(allocated_ptr[0..idle_stack_end_offset]);230 gpa.free(allocated_ptr[0..idle_stack_end_offset]);
206 k.* = undefined;231 k.* = undefined;
207}232}
208233
...@@ -317,6 +342,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {...@@ -317,6 +342,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void {
317 },342 },
318 .idle_search_index = 0,343 .idle_search_index = 0,
319 .steal_ready_search_index = 0,344 .steal_ready_search_index = 0,
345 .wait_queues = .empty,
320 };346 };
321 new_thread.thread = std.Thread.spawn(.{347 new_thread.thread = std.Thread.spawn(.{
322 .stack_size = idle_stack_size,348 .stack_size = idle_stack_size,
...@@ -355,6 +381,7 @@ fn threadEntry(k: *Kqueue, index: u32) void {...@@ -355,6 +381,7 @@ fn threadEntry(k: *Kqueue, index: u32) void {
355 Thread.self = thread;381 Thread.self = thread;
356 std.log.debug("created thread idle {*}", .{&thread.idle_context});382 std.log.debug("created thread idle {*}", .{&thread.idle_context});
357 k.idle(thread);383 k.idle(thread);
384 thread.deinit(k.gpa);
358}385}
359386
360const Completion = struct {387const Completion = struct {