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 }