| ... | @@ -148,6 +148,16 @@ pub const Config = struct { | ... | @@ -148,6 +148,16 @@ pub const Config = struct { |
| 148 | /// Whether the allocator may be used simultaneously from multiple threads. | 148 | /// Whether the allocator may be used simultaneously from multiple threads. |
| 149 | thread_safe: bool = !std.builtin.single_threaded, | 149 | thread_safe: bool = !std.builtin.single_threaded, |
| 150 | | 150 | |
| | 151 | /// What type of mutex you'd like to use, for thread safety. |
| | 152 | /// when specfied, the mutex type must have the same shape as `std.Mutex` and |
| | 153 | /// `std.mutex.Dummy`, and have no required fields. Specifying this field causes |
| | 154 | /// the `thread_safe` field to be ignored. |
| | 155 | /// |
| | 156 | /// when null (default): |
| | 157 | /// * the mutex type defaults to `std.Mutex` when thread_safe is enabled. |
| | 158 | /// * the mutex type defaults to `std.mutex.Dummy` otherwise. |
| | 159 | MutexType: ?type = null, |
| | 160 | |
| 151 | /// This is a temporary debugging trick you can use to turn segfaults into more helpful | 161 | /// This is a temporary debugging trick you can use to turn segfaults into more helpful |
| 152 | /// logged error messages with stack trace details. The downside is that every allocation | 162 | /// logged error messages with stack trace details. The downside is that every allocation |
| 153 | /// will be leaked! | 163 | /// will be leaked! |
| ... | @@ -174,7 +184,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { | ... | @@ -174,7 +184,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type { |
| 174 | const total_requested_bytes_init = if (config.enable_memory_limit) @as(usize, 0) else {}; | 184 | const total_requested_bytes_init = if (config.enable_memory_limit) @as(usize, 0) else {}; |
| 175 | const requested_memory_limit_init = if (config.enable_memory_limit) @as(usize, math.maxInt(usize)) else {}; | 185 | const requested_memory_limit_init = if (config.enable_memory_limit) @as(usize, math.maxInt(usize)) else {}; |
| 176 | | 186 | |
| 177 | const mutex_init = if (config.thread_safe) std.Mutex{} else std.mutex.Dummy{}; | 187 | const mutex_init = if (config.MutexType) |T| T{} else |
| | 188 | if (config.thread_safe) std.Mutex{} else std.mutex.Dummy{}; |
| 178 | | 189 | |
| 179 | const stack_n = config.stack_trace_frames; | 190 | const stack_n = config.stack_trace_frames; |
| 180 | const one_trace_size = @sizeOf(usize) * stack_n; | 191 | const one_trace_size = @sizeOf(usize) * stack_n; |
| ... | @@ -849,6 +860,18 @@ test "realloc large object to small object" { | ... | @@ -849,6 +860,18 @@ test "realloc large object to small object" { |
| 849 | std.testing.expect(slice[16] == 0x34); | 860 | std.testing.expect(slice[16] == 0x34); |
| 850 | } | 861 | } |
| 851 | | 862 | |
| | 863 | test "overrideable mutexes" { |
| | 864 | var gpa = GeneralPurposeAllocator(.{.MutexType = std.Mutex}){ |
| | 865 | .backing_allocator = std.testing.allocator, |
| | 866 | .mutex = std.Mutex{} |
| | 867 | }; |
| | 868 | defer std.testing.expect(!gpa.deinit()); |
| | 869 | const allocator = &gpa.allocator; |
| | 870 | |
| | 871 | const ptr = try allocator.create(i32); |
| | 872 | defer allocator.destroy(ptr); |
| | 873 | } |
| | 874 | |
| 852 | test "non-page-allocator backing allocator" { | 875 | test "non-page-allocator backing allocator" { |
| 853 | var gpa = GeneralPurposeAllocator(.{}){ .backing_allocator = std.testing.allocator }; | 876 | var gpa = GeneralPurposeAllocator(.{}){ .backing_allocator = std.testing.allocator }; |
| 854 | defer std.testing.expect(!gpa.deinit()); | 877 | defer std.testing.expect(!gpa.deinit()); |