| ... | ... | @@ -157,8 +157,11 @@ pub const InitOptions = struct { |
| 157 | 157 | n_threads: ?usize = null, |
| 158 | 158 | }; |
| 159 | 159 | |
| 160 | pub const InitError = Allocator.Error || CreateFileDescriptorError; |
| 161 | |
| 160 | 162 | pub fn init(k: *Kqueue, gpa: Allocator, options: InitOptions) !void { |
| 161 | 163 | assert(options.n_threads != 0); |
| 164 | |
| 162 | 165 | const n_threads = @max(1, options.n_threads orelse std.Thread.getCpuCount() catch 1); |
| 163 | 166 | const threads_size = n_threads * @sizeOf(Thread); |
| 164 | 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 | 207 | }, |
| 205 | 208 | .current_context = &main_fiber.context, |
| 206 | 209 | .ready_queue = null, |
| 207 | | .kq_fd = try posix.kqueue(), |
| 210 | .kq_fd = try createFileDescriptor(), |
| 208 | 211 | .idle_search_index = 1, |
| 209 | 212 | .steal_ready_search_index = 1, |
| 210 | 213 | .wait_queues = .empty, |
| ... | ... | @@ -231,6 +234,23 @@ pub fn deinit(k: *Kqueue) void { |
| 231 | 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 | 254 | fn findReadyFiber(k: *Kqueue, thread: *Thread) ?*Fiber { |
| 235 | 255 | if (@atomicRmw(?*Fiber, &thread.ready_queue, .Xchg, Fiber.finished, .acquire)) |ready_fiber| { |
| 236 | 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 | 354 | .idle_context = undefined, |
| 335 | 355 | .current_context = &new_thread.idle_context, |
| 336 | 356 | .ready_queue = ready_queue.head, |
| 337 | | .kq_fd = posix.kqueue() catch |err| { |
| 357 | .kq_fd = createFileDescriptor() catch |err| { |
| 338 | 358 | @atomicStore(u32, &k.threads.reserved, new_thread_index, .release); |
| 339 | 359 | // no more access to `thread` after giving up reservation |
| 340 | 360 | std.log.warn("unable to create worker thread due to kqueue init failure: {t}", .{err}); |