| ... | @@ -157,8 +157,11 @@ pub const InitOptions = struct { | ... | @@ -157,8 +157,11 @@ pub const InitOptions = struct { |
| 157 | n_threads: ?usize = null, | 157 | n_threads: ?usize = null, |
| 158 | }; | 158 | }; |
| 159 | | 159 | |
| | 160 | pub const InitError = Allocator.Error || CreateFileDescriptorError; |
| | 161 | |
| 160 | pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void { | 162 | pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void { |
| 161 | assert(options.n_threads != 0); | 163 | assert(options.n_threads != 0); |
| | 164 | |
| 162 | const n_threads = @max(1, options.n_threads orelse std.Thread.getCpuCount() catch 1); | 165 | const n_threads = @max(1, options.n_threads orelse std.Thread.getCpuCount() catch 1); |
| 163 | const threads_size = n_threads * @sizeOf(Thread); | 166 | const threads_size = n_threads * @sizeOf(Thread); |
| 164 | const idle_stack_end_offset = std.mem.alignForward(usize, threads_size + idle_stack_size, std.heap.page_size_max); | 167 | const idle_stack_end_offset = std.mem.alignForward(usize, threads_size + idle_stack_size, std.heap.page_size_max); |
| ... | @@ -204,7 +207,7 @@ pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void { | ... | @@ -204,7 +207,7 @@ pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void { |
| 204 | }, | 207 | }, |
| 205 | .current_context = &main_fiber.context, | 208 | .current_context = &main_fiber.context, |
| 206 | .ready_queue = null, | 209 | .ready_queue = null, |
| 207 | .kq_fd = try posix.kqueue(), | 210 | .kq_fd = try createFileDescriptor(), |
| 208 | .idle_search_index = 1, | 211 | .idle_search_index = 1, |
| 209 | .steal_ready_search_index = 1, | 212 | .steal_ready_search_index = 1, |
| 210 | .wait_queues = .empty, | 213 | .wait_queues = .empty, |
| ... | @@ -231,6 +234,23 @@ pub fn deinit(k: *Kqueue) void { | ... | @@ -231,6 +234,23 @@ pub fn deinit(k: *Kqueue) void { |
| 231 | k.* = undefined; | 234 | k.* = undefined; |
| 232 | } | 235 | } |
| 233 | | 236 | |
| | 237 | pub const CreateFileDescriptorError = error{ |
| | 238 | /// The per-process limit on the number of open file descriptors has been reached. |
| | 239 | ProcessFdQuotaExceeded, |
| | 240 | /// The system-wide limit on the total number of open files has been reached. |
| | 241 | SystemFdQuotaExceeded, |
| | 242 | } || Io.Unexpected; |
| | 243 | |
| | 244 | pub fn createFileDescriptor() CreateFileDescriptorError!posix.fd_t { |
| | 245 | const rc = posix.system.kqueue(); |
| | 246 | switch (posix.errno(rc)) { |
| | 247 | .SUCCESS => return @intCast(rc), |
| | 248 | .MFILE => return error.ProcessFdQuotaExceeded, |
| | 249 | .NFILE => return error.SystemFdQuotaExceeded, |
| | 250 | else => |err| return posix.unexpectedErrno(err), |
| | 251 | } |
| | 252 | } |
| | 253 | |
| 234 | fn findReadyFiber(k: *Kqueue, thread: *Thread) ?*Fiber { | 254 | fn findReadyFiber(k: *Kqueue, thread: *Thread) ?*Fiber { |
| 235 | if (@atomicRmw(?*Fiber, &thread.ready_queue, .Xchg, Fiber.finished, .acquire)) |ready_fiber| { | 255 | if (@atomicRmw(?*Fiber, &thread.ready_queue, .Xchg, Fiber.finished, .acquire)) |ready_fiber| { |
| 236 | @atomicStore(?*Fiber, &thread.ready_queue, ready_fiber.queue_next, .release); | 256 | @atomicStore(?*Fiber, &thread.ready_queue, ready_fiber.queue_next, .release); |
| ... | @@ -334,7 +354,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void { | ... | @@ -334,7 +354,7 @@ fn schedule(k: *Kqueue, thread: *Thread, ready_queue: Fiber.Queue) void { |
| 334 | .idle_context = undefined, | 354 | .idle_context = undefined, |
| 335 | .current_context = &new_thread.idle_context, | 355 | .current_context = &new_thread.idle_context, |
| 336 | .ready_queue = ready_queue.head, | 356 | .ready_queue = ready_queue.head, |
| 337 | .kq_fd = posix.kqueue() catch |err| { | 357 | .kq_fd = createFileDescriptor() catch |err| { |
| 338 | @atomicStore(u32, &k.threads.reserved, new_thread_index, .release); | 358 | @atomicStore(u32, &k.threads.reserved, new_thread_index, .release); |
| 339 | // no more access to `thread` after giving up reservation | 359 | // no more access to `thread` after giving up reservation |
| 340 | std.log.warn("unable to create worker thread due to kqueue init failure: {t}", .{err}); | 360 | std.log.warn("unable to create worker thread due to kqueue init failure: {t}", .{err}); |