| ... | @@ -36,9 +36,9 @@ pub fn threadSafeAllocator(self: *FixedBufferAllocator) Allocator { | ... | @@ -36,9 +36,9 @@ pub fn threadSafeAllocator(self: *FixedBufferAllocator) Allocator { |
| 36 | .ptr = self, | 36 | .ptr = self, |
| 37 | .vtable = &.{ | 37 | .vtable = &.{ |
| 38 | .alloc = threadSafeAlloc, | 38 | .alloc = threadSafeAlloc, |
| 39 | .resize = Allocator.noResize, | 39 | .resize = threadSafeResize, |
| 40 | .remap = Allocator.noRemap, | 40 | .remap = threadSafeRemap, |
| 41 | .free = Allocator.noFree, | 41 | .free = threadSafeFree, |
| 42 | }, | 42 | }, |
| 43 | }; | 43 | }; |
| 44 | } | 44 | } |
| ... | @@ -127,21 +127,84 @@ pub fn free( | ... | @@ -127,21 +127,84 @@ pub fn free( |
| 127 | } | 127 | } |
| 128 | } | 128 | } |
| 129 | | 129 | |
| 130 | fn threadSafeAlloc(ctx: *anyopaque, n: usize, alignment: mem.Alignment, ra: usize) ?[*]u8 { | 130 | fn threadSafeAlloc(ctx: *anyopaque, n: usize, alignment: mem.Alignment, ret_addr: usize) ?[*]u8 { |
| 131 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); | 131 | const self: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); |
| 132 | _ = ra; | 132 | _ = ret_addr; |
| 133 | const ptr_align = alignment.toByteUnits(); | 133 | const ptr_align = alignment.toByteUnits(); |
| 134 | var end_index = @atomicLoad(usize, &self.end_index, .seq_cst); | 134 | var cur_end_index = @atomicLoad(usize, &self.end_index, .monotonic); |
| 135 | while (true) { | 135 | while (true) { |
| 136 | const adjust_off = mem.alignPointerOffset(self.buffer.ptr + end_index, ptr_align) orelse return null; | 136 | const adjust_off = mem.alignPointerOffset(self.buffer.ptr + cur_end_index, ptr_align) orelse return null; |
| 137 | const adjusted_index = end_index + adjust_off; | 137 | const adjusted_index = cur_end_index + adjust_off; |
| 138 | const new_end_index = adjusted_index + n; | 138 | const new_end_index = adjusted_index + n; |
| 139 | if (new_end_index > self.buffer.len) return null; | 139 | if (new_end_index > self.buffer.len) return null; |
| 140 | end_index = @cmpxchgWeak(usize, &self.end_index, end_index, new_end_index, .seq_cst, .seq_cst) orelse | 140 | cur_end_index = @cmpxchgWeak(usize, &self.end_index, cur_end_index, new_end_index, .monotonic, .monotonic) orelse |
| 141 | return self.buffer[adjusted_index..new_end_index].ptr; | 141 | return self.buffer[adjusted_index..new_end_index].ptr; |
| 142 | } | 142 | } |
| 143 | } | 143 | } |
| 144 | | 144 | |
| | 145 | fn threadSafeResize(ctx: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: usize, ret_addr: usize) bool { |
| | 146 | const fba: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); |
| | 147 | _ = alignment; |
| | 148 | _ = ret_addr; |
| | 149 | |
| | 150 | const cur_end_index = @atomicLoad(usize, &fba.end_index, .monotonic); |
| | 151 | if (fba.buffer.ptr + cur_end_index != memory.ptr + memory.len) { |
| | 152 | // It's not the most recent allocation, so it cannot be expanded, |
| | 153 | // but it's fine if they want to make it smaller. |
| | 154 | return new_len <= memory.len; |
| | 155 | } |
| | 156 | |
| | 157 | const new_end_index: usize = new_end_index: { |
| | 158 | if (memory.len >= new_len) { |
| | 159 | break :new_end_index cur_end_index - (memory.len - new_len); |
| | 160 | } |
| | 161 | if (fba.buffer.len - cur_end_index >= new_len - memory.len) { |
| | 162 | break :new_end_index cur_end_index + (new_len - memory.len); |
| | 163 | } |
| | 164 | return false; |
| | 165 | }; |
| | 166 | assert(fba.buffer.ptr + new_end_index == memory.ptr + new_len); |
| | 167 | |
| | 168 | return null == @cmpxchgStrong( |
| | 169 | usize, |
| | 170 | &fba.end_index, |
| | 171 | cur_end_index, |
| | 172 | new_end_index, |
| | 173 | .monotonic, |
| | 174 | .monotonic, |
| | 175 | ); |
| | 176 | } |
| | 177 | |
| | 178 | fn threadSafeRemap(ctx: *anyopaque, memory: []u8, alignment: mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { |
| | 179 | return if (threadSafeResize(ctx, memory, alignment, new_len, ret_addr)) memory.ptr else null; |
| | 180 | } |
| | 181 | |
| | 182 | fn threadSafeFree(ctx: *anyopaque, memory: []u8, alignment: mem.Alignment, ret_addr: usize) void { |
| | 183 | const fba: *FixedBufferAllocator = @ptrCast(@alignCast(ctx)); |
| | 184 | _ = alignment; |
| | 185 | _ = ret_addr; |
| | 186 | |
| | 187 | assert(memory.len > 0); |
| | 188 | |
| | 189 | const cur_end_index = @atomicLoad(usize, &fba.end_index, .monotonic); |
| | 190 | if (fba.buffer.ptr + cur_end_index != memory.ptr + memory.len) { |
| | 191 | // Not the most recent allocation; we cannot free it. |
| | 192 | return; |
| | 193 | } |
| | 194 | |
| | 195 | const new_end_index = cur_end_index - memory.len; |
| | 196 | assert(fba.buffer.ptr + new_end_index == memory.ptr); |
| | 197 | |
| | 198 | _ = @cmpxchgStrong( |
| | 199 | usize, |
| | 200 | &fba.end_index, |
| | 201 | cur_end_index, |
| | 202 | new_end_index, |
| | 203 | .monotonic, |
| | 204 | .monotonic, |
| | 205 | ); |
| | 206 | } |
| | 207 | |
| 145 | pub fn reset(self: *FixedBufferAllocator) void { | 208 | pub fn reset(self: *FixedBufferAllocator) void { |
| 146 | self.end_index = 0; | 209 | self.end_index = 0; |
| 147 | } | 210 | } |