diff options
Diffstat (limited to 'src/memory.zig')
| -rw-r--r-- | src/memory.zig | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/src/memory.zig b/src/memory.zig index f30e4392..e5394b4f 100644 --- a/src/memory.zig +++ b/src/memory.zig @@ -44,7 +44,48 @@ pub const Allocators = struct { pdf: Allocator, }; -var pardes_fallback: std.heap.StackFallbackAllocator(limits.arena.pardes) = undefined; +/// `std.heap.StackFallbackAllocator` with the buffer taken through its +/// lock-free interface. The core's allocator is used from two threads: a 9P +/// connection task answers a request while the editor's own thread is out +/// in a syscall that allocates (`readFileLimit`, `grep`; see `pardes.turn`). +fn SharedStackFallback(comptime size: usize) type { + return struct { + buffer: [size]u8 = undefined, + fallback_allocator: Allocator = undefined, + fixed: std.heap.FixedBufferAllocator = undefined, + + fn get(self: *@This()) Allocator { + self.fixed = .init(self.buffer[0..]); + return .{ .ptr = self, .vtable = &.{ .alloc = alloc, .resize = resize, .remap = remap, .free = free } }; + } + + fn alloc(ctx: *anyopaque, len: usize, alignment: std.mem.Alignment, ra: usize) ?[*]u8 { + const self: *@This() = @ptrCast(@alignCast(ctx)); + return self.fixed.threadSafeAllocator().rawAlloc(len, alignment, ra) orelse + self.fallback_allocator.rawAlloc(len, alignment, ra); + } + + fn resize(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, new_len: usize, ra: usize) bool { + const self: *@This() = @ptrCast(@alignCast(ctx)); + if (self.fixed.ownsPtr(buf.ptr)) return self.fixed.threadSafeAllocator().rawResize(buf, alignment, new_len, ra); + return self.fallback_allocator.rawResize(buf, alignment, new_len, ra); + } + + fn remap(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, new_len: usize, ra: usize) ?[*]u8 { + const self: *@This() = @ptrCast(@alignCast(ctx)); + if (self.fixed.ownsPtr(buf.ptr)) return self.fixed.threadSafeAllocator().rawRemap(buf, alignment, new_len, ra); + return self.fallback_allocator.rawRemap(buf, alignment, new_len, ra); + } + + fn free(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, ra: usize) void { + const self: *@This() = @ptrCast(@alignCast(ctx)); + if (self.fixed.ownsPtr(buf.ptr)) return self.fixed.threadSafeAllocator().rawFree(buf, alignment, ra); + return self.fallback_allocator.rawFree(buf, alignment, ra); + } + }; +} + +var pardes_fallback: SharedStackFallback(limits.arena.pardes) = .{}; var frame_fallback: std.heap.StackFallbackAllocator(limits.arena.frame) = undefined; var tree_sitter_fallback: std.heap.StackFallbackAllocator(limits.arena.tree_sitter) = undefined; var image_fallback: std.heap.StackFallbackAllocator(limits.arena.image) = undefined; @@ -61,7 +102,6 @@ var pdf_debug: Debug = .init; // One session at a time; free its allocations before deinit. Concurrent LSP workers use the caller's allocator. pub fn init(fallback: Allocator) Allocators { pardes_fallback.fallback_allocator = fallback; - pardes_fallback.get_called = if (std.debug.runtime_safety) false else {}; frame_fallback.fallback_allocator = fallback; frame_fallback.get_called = if (std.debug.runtime_safety) false else {}; tree_sitter_fallback.fallback_allocator = fallback; @@ -112,12 +152,12 @@ test "fixed allocators are separate, spill, and restart" { var allocs = init(std.testing.allocator); const core = try allocs.pardes.alloc(u8, 32); const frame = try allocs.frame.alloc(u8, 32); - try std.testing.expect(pardes_fallback.fixed_buffer_allocator.ownsPtr(core.ptr)); + try std.testing.expect(pardes_fallback.fixed.ownsPtr(core.ptr)); try std.testing.expect(frame_fallback.fixed_buffer_allocator.ownsPtr(frame.ptr)); try std.testing.expect(core.ptr != frame.ptr); const spill = try allocs.pardes.alloc(u8, limits.arena.pardes + 1); - try std.testing.expect(!pardes_fallback.fixed_buffer_allocator.ownsPtr(spill.ptr)); + try std.testing.expect(!pardes_fallback.fixed.ownsPtr(spill.ptr)); allocs.pardes.free(spill); allocs.frame.free(frame); allocs.pardes.free(core); @@ -127,7 +167,7 @@ test "fixed allocators are separate, spill, and restart" { defer deinit(); const restarted = try allocs.pardes.alloc(u8, 32); defer allocs.pardes.free(restarted); - try std.testing.expect(pardes_fallback.fixed_buffer_allocator.ownsPtr(restarted.ptr)); + try std.testing.expect(pardes_fallback.fixed.ownsPtr(restarted.ptr)); } test "memory limits preserve desktop capacities" { |
