| ... | ... | @@ -0,0 +1,45 @@ |
| 1 | //! Wraps a non-thread-safe allocator and makes it thread-safe. |
| 2 | |
| 3 | child_allocator: Allocator, |
| 4 | mutex: std.Thread.Mutex = .{}, |
| 5 | |
| 6 | pub fn allocator(self: *ThreadSafeAllocator) Allocator { |
| 7 | return .{ |
| 8 | .ptr = self, |
| 9 | .vtable = &.{ |
| 10 | .alloc = alloc, |
| 11 | .resize = resize, |
| 12 | .free = free, |
| 13 | }, |
| 14 | }; |
| 15 | } |
| 16 | |
| 17 | fn alloc(ctx: *anyopaque, n: usize, log2_ptr_align: u8, ra: usize) ?[*]u8 { |
| 18 | const self = @ptrCast(*ThreadSafeAllocator, @alignCast(@alignOf(ThreadSafeAllocator), ctx)); |
| 19 | self.mutex.lock(); |
| 20 | defer self.mutex.unlock(); |
| 21 | |
| 22 | return self.child_allocator.rawAlloc(n, log2_ptr_align, ra); |
| 23 | } |
| 24 | |
| 25 | fn resize(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, new_len: usize, ret_addr: usize) bool { |
| 26 | const self = @ptrCast(*ThreadSafeAllocator, @alignCast(@alignOf(ThreadSafeAllocator), ctx)); |
| 27 | |
| 28 | self.mutex.lock(); |
| 29 | defer self.mutex.unlock(); |
| 30 | |
| 31 | return self.child_allocator.rawResize(buf, log2_buf_align, new_len, ret_addr); |
| 32 | } |
| 33 | |
| 34 | fn free(ctx: *anyopaque, buf: []u8, log2_buf_align: u8, ret_addr: usize) void { |
| 35 | const self = @ptrCast(*ThreadSafeAllocator, @alignCast(@alignOf(ThreadSafeAllocator), ctx)); |
| 36 | |
| 37 | self.mutex.lock(); |
| 38 | defer self.mutex.unlock(); |
| 39 | |
| 40 | return self.child_allocator.rawFree(buf, log2_buf_align, ret_addr); |
| 41 | } |
| 42 | |
| 43 | const std = @import("../std.zig"); |
| 44 | const ThreadSafeAllocator = @This(); |
| 45 | const Allocator = std.mem.Allocator; |