| ... | @@ -12,15 +12,18 @@ const maxInt = std.math.maxInt; | ... | @@ -12,15 +12,18 @@ const maxInt = std.math.maxInt; |
| 12 | const Thread = std.Thread; | 12 | const Thread = std.Thread; |
| 13 | | 13 | |
| 14 | pub const Loop = struct { | 14 | pub const Loop = struct { |
| 15 | allocator: *mem.Allocator, | | |
| 16 | next_tick_queue: std.atomic.Queue(anyframe), | 15 | next_tick_queue: std.atomic.Queue(anyframe), |
| 17 | os_data: OsData, | 16 | os_data: OsData, |
| 18 | final_resume_node: ResumeNode, | 17 | final_resume_node: ResumeNode, |
| 19 | pending_event_count: usize, | 18 | pending_event_count: usize, |
| 20 | extra_threads: []*Thread, | 19 | extra_threads: []*Thread, |
| 21 | | 20 | |
| 22 | // pre-allocated eventfds. all permanently active. | 21 | /// For resources that have the same lifetime as the `Loop`. |
| 23 | // this is how we send promises to be resumed on other threads. | 22 | /// This is only used by `Loop` for the thread pool and associated resources. |
| | 23 | arena: std.heap.ArenaAllocator, |
| | 24 | |
| | 25 | /// Pre-allocated eventfds. All permanently active. |
| | 26 | /// This is how `Loop` sends promises to be resumed on other threads. |
| 24 | available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd), | 27 | available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd), |
| 25 | eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node, | 28 | eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node, |
| 26 | | 29 | |
| ... | @@ -127,11 +130,9 @@ pub const Loop = struct { | ... | @@ -127,11 +130,9 @@ pub const Loop = struct { |
| 127 | /// Thread count is the total thread count. The thread pool size will be | 130 | /// Thread count is the total thread count. The thread pool size will be |
| 128 | /// max(thread_count - 1, 0) | 131 | /// max(thread_count - 1, 0) |
| 129 | pub fn initThreadPool(self: *Loop, thread_count: usize) !void { | 132 | pub fn initThreadPool(self: *Loop, thread_count: usize) !void { |
| 130 | // TODO: https://github.com/ziglang/zig/issues/3539 | | |
| 131 | const allocator = std.heap.page_allocator; | | |
| 132 | self.* = Loop{ | 133 | self.* = Loop{ |
| | 134 | .arena = std.heap.ArenaAllocator.init(std.heap.page_allocator), |
| 133 | .pending_event_count = 1, | 135 | .pending_event_count = 1, |
| 134 | .allocator = allocator, | | |
| 135 | .os_data = undefined, | 136 | .os_data = undefined, |
| 136 | .next_tick_queue = std.atomic.Queue(anyframe).init(), | 137 | .next_tick_queue = std.atomic.Queue(anyframe).init(), |
| 137 | .extra_threads = undefined, | 138 | .extra_threads = undefined, |
| ... | @@ -143,17 +144,17 @@ pub const Loop = struct { | ... | @@ -143,17 +144,17 @@ pub const Loop = struct { |
| 143 | .overlapped = ResumeNode.overlapped_init, | 144 | .overlapped = ResumeNode.overlapped_init, |
| 144 | }, | 145 | }, |
| 145 | }; | 146 | }; |
| | 147 | errdefer self.arena.deinit(); |
| | 148 | |
| 146 | // We need at least one of these in case the fs thread wants to use onNextTick | 149 | // We need at least one of these in case the fs thread wants to use onNextTick |
| 147 | const extra_thread_count = thread_count - 1; | 150 | const extra_thread_count = thread_count - 1; |
| 148 | const resume_node_count = std.math.max(extra_thread_count, 1); | 151 | const resume_node_count = std.math.max(extra_thread_count, 1); |
| 149 | self.eventfd_resume_nodes = try self.allocator.alloc( | 152 | self.eventfd_resume_nodes = try self.arena.allocator.alloc( |
| 150 | std.atomic.Stack(ResumeNode.EventFd).Node, | 153 | std.atomic.Stack(ResumeNode.EventFd).Node, |
| 151 | resume_node_count, | 154 | resume_node_count, |
| 152 | ); | 155 | ); |
| 153 | errdefer self.allocator.free(self.eventfd_resume_nodes); | | |
| 154 | | 156 | |
| 155 | self.extra_threads = try self.allocator.alloc(*Thread, extra_thread_count); | 157 | self.extra_threads = try self.arena.allocator.alloc(*Thread, extra_thread_count); |
| 156 | errdefer self.allocator.free(self.extra_threads); | | |
| 157 | | 158 | |
| 158 | try self.initOsData(extra_thread_count); | 159 | try self.initOsData(extra_thread_count); |
| 159 | errdefer self.deinitOsData(); | 160 | errdefer self.deinitOsData(); |
| ... | @@ -161,7 +162,8 @@ pub const Loop = struct { | ... | @@ -161,7 +162,8 @@ pub const Loop = struct { |
| 161 | | 162 | |
| 162 | pub fn deinit(self: *Loop) void { | 163 | pub fn deinit(self: *Loop) void { |
| 163 | self.deinitOsData(); | 164 | self.deinitOsData(); |
| 164 | self.allocator.free(self.extra_threads); | 165 | self.arena.deinit(); |
| | 166 | self.* = undefined; |
| 165 | } | 167 | } |
| 166 | | 168 | |
| 167 | const InitOsDataError = os.EpollCreateError || mem.Allocator.Error || os.EventFdError || | 169 | const InitOsDataError = os.EpollCreateError || mem.Allocator.Error || os.EventFdError || |
| ... | @@ -407,7 +409,6 @@ pub const Loop = struct { | ... | @@ -407,7 +409,6 @@ pub const Loop = struct { |
| 407 | noasync os.close(self.os_data.final_eventfd); | 409 | noasync os.close(self.os_data.final_eventfd); |
| 408 | while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd); | 410 | while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd); |
| 409 | noasync os.close(self.os_data.epollfd); | 411 | noasync os.close(self.os_data.epollfd); |
| 410 | self.allocator.free(self.eventfd_resume_nodes); | | |
| 411 | }, | 412 | }, |
| 412 | .macosx, .freebsd, .netbsd, .dragonfly => { | 413 | .macosx, .freebsd, .netbsd, .dragonfly => { |
| 413 | noasync os.close(self.os_data.kqfd); | 414 | noasync os.close(self.os_data.kqfd); |