lib/alloc/src/policy.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const builtin = @import("builtin");
  3 const build_options = @import("build_options");
  4 const diagnostics = @import("diagnostics.zig");
  5 const heap = @import("heap.zig");
  6 const process = @import("process.zig");
  7 
  8 const Allocator = std.mem.Allocator;
  9 
 10 pub const TestAllocatorMode = enum {
 11     fast,
 12     leak_check,
 13 };
 14 
 15 pub const test_allocator_mode: TestAllocatorMode = parseTestAllocatorMode();
 16 
 17 /// Returns the allocator for storage that lives for the whole process. Which
 18 /// allocator that is comes from the build's diagnostics setting and its phase
 19 /// setting. Everything taken from it goes back through it before the process
 20 /// finishes tearing down.
 21 pub fn longLivedProcessAllocator() Allocator {
 22     return platformProcessAllocator();
 23 }
 24 
 25 /// Returns the allocator for storage that stays valid for the session around
 26 /// the call. Memory taken from it goes back through the same allocator. It uses
 27 /// the `fallback` the caller passes in two cases: a test build running the
 28 /// leak-checking policy, and a WebAssembly target. Everywhere else it returns
 29 /// the process allocator.
 30 pub fn interactiveSessionAllocator(fallback: Allocator) Allocator {
 31     if (comptime builtin.is_test) return testAllocatorForMode(fallback);
 32     if (comptime diagnostics.config() != null) return platformProcessAllocator();
 33     if (comptime builtin.cpu.arch.isWasm()) return fallback;
 34     return platformProcessAllocator();
 35 }
 36 
 37 pub fn standaloneProcessAllocator() Allocator {
 38     if (comptime builtin.is_test) return testIntegrationAllocator();
 39     return platformProcessAllocator();
 40 }
 41 
 42 pub fn workerAllocator() Allocator {
 43     if (comptime builtin.is_test) return testIntegrationAllocator();
 44     return platformProcessAllocator();
 45 }
 46 
 47 pub fn threadedIoAllocator() Allocator {
 48     return workerAllocator();
 49 }
 50 
 51 pub fn temporaryScratchAllocator() Allocator {
 52     if (comptime builtin.is_test) return testIntegrationAllocator();
 53     return platformProcessAllocator();
 54 }
 55 
 56 pub fn testIntegrationAllocator() Allocator {
 57     if (comptime !builtin.is_test) @compileError("testIntegrationAllocator is test-only");
 58     return testAllocatorForMode(std.testing.allocator);
 59 }
 60 
 61 pub fn platformProcessAllocator() Allocator {
 62     if (comptime diagnostics.config()) |diagnostic_config| {
 63         if (@inComptime()) @compileError("allocator diagnostics require runtime allocator selection");
 64         return process.wrap(diagnostics.processAllocator(diagnostic_config));
 65     }
 66     if (comptime process.mode == .off) return heap.processHeapAllocator();
 67     if (@inComptime()) @compileError("allocator phase enforcement requires runtime allocator selection");
 68     return process.wrap(heap.processHeapAllocator());
 69 }
 70 
 71 /// Marks the moment startup is over, after which the package can tell a startup
 72 /// allocation from a later one: it ends the initialization phase of the process
 73 /// allocator. A caller makes this call once, after the storage it needs at
 74 /// startup has been taken. What happens to an allocation that arrives after the
 75 /// seal is decided by the process phase mode: under `observe` it is counted and
 76 /// goes through, and under `seal` it panics. Under the `off` mode the call does
 77 /// nothing.
 78 pub fn sealProcessAllocatorPhase() void {
 79     if (comptime process.mode == .off) return;
 80     _ = platformProcessAllocator();
 81     process.seal();
 82 }
 83 
 84 /// Opens the teardown phase, so a free that follows counts as no violation and
 85 /// a caller can release the storage taken at startup. A caller makes this call
 86 /// after steady work has stopped and before releasing the storage that lives as
 87 /// long as the process. Under the `off` mode the call does nothing.
 88 pub fn beginProcessAllocatorTeardown() void {
 89     if (comptime process.mode == .off) return;
 90     _ = platformProcessAllocator();
 91     process.beginTeardown();
 92 }
 93 
 94 fn testAllocatorForMode(leak_allocator: Allocator) Allocator {
 95     if (comptime !builtin.is_test) @compileError("testAllocatorForMode is test-only");
 96     return switch (test_allocator_mode) {
 97         .fast => platformProcessAllocator(),
 98         .leak_check => leak_allocator,
 99     };
100 }
101 
102 fn parseTestAllocatorMode() TestAllocatorMode {
103     if (std.mem.eql(u8, build_options.test_allocator_mode, "fast")) return .fast;
104     if (std.mem.eql(u8, build_options.test_allocator_mode, "leak_check")) return .leak_check;
105     @compileError("unknown test allocator mode");
106 }