lib/alloc/src/process.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const build_options = @import("build_options");
3
4 const phase = @import("alloc_phase");
5
6 const Allocator = std.mem.Allocator;
7
8 pub const ProcessPhaseMode = enum {
9 off,
10 observe,
11 seal,
12 };
13
14 pub const mode: ProcessPhaseMode = parseMode();
15
16 const ProcessPhaseAllocator = switch (mode) {
17 .off => void,
18 .observe => phase.ObservingPhaseAllocator,
19 .seal => phase.SealedPhaseAllocator,
20 };
21
22 var lock: std.atomic.Mutex = .unlocked;
23 var initialized = false;
24 var storage: ProcessPhaseAllocator = undefined;
25 var handle: Allocator = undefined;
26
27 pub fn wrap(backing: Allocator) Allocator {
28 if (comptime mode == .off) return backing;
29 lockInit();
30 defer unlockInit();
31 if (!initialized) {
32 storage = ProcessPhaseAllocator.init(backing) catch
33 @panic("out of memory initializing process allocator phase");
34 handle = storage.initializationAllocator();
35 initialized = true;
36 }
37 return handle;
38 }
39
40 pub fn seal() void {
41 if (comptime mode == .off) return;
42 lockInit();
43 defer unlockInit();
44 if (!initialized) @panic("process allocator phase sealed before first use");
45 storage.seal();
46 }
47
48 pub fn beginTeardown() void {
49 if (comptime mode == .off) return;
50 lockInit();
51 defer unlockInit();
52 if (!initialized) @panic("process allocator phase teardown before first use");
53 storage.beginTeardown();
54 }
55
56 pub fn violations() ?phase.PhaseViolations {
57 if (comptime mode == .off) return null;
58 lockInit();
59 defer unlockInit();
60 if (!initialized) return .{};
61 return storage.violations();
62 }
63
64 pub fn violationSites() ?phase.ViolationSites {
65 if (comptime mode != .observe) return null;
66 lockInit();
67 defer unlockInit();
68 if (!initialized) return .{};
69 return storage.violationSites();
70 }
71
72 pub fn currentPhase() ?phase.capacity.Phase {
73 if (comptime mode == .off) return null;
74 lockInit();
75 defer unlockInit();
76 if (!initialized) return .initialization;
77 return storage.phase();
78 }
79
80 fn parseMode() ProcessPhaseMode {
81 if (std.mem.eql(u8, build_options.allocator_phase, "off")) return .off;
82 if (std.mem.eql(u8, build_options.allocator_phase, "observe")) return .observe;
83 if (std.mem.eql(u8, build_options.allocator_phase, "seal")) return .seal;
84 @compileError("unknown allocator phase mode");
85 }
86
87 fn lockInit() void {
88 while (!lock.tryLock()) std.atomic.spinLoopHint();
89 }
90
91 fn unlockInit() void {
92 lock.unlock();
93 }