lib/alloc/src/boundary.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 const policy = @import("policy.zig");
 4 const process = @import("process.zig");
 5 
 6 pub const PhaseBoundaryState = struct {
 7     phase: Phase = .initialization,
 8     sealed: bool = false,
 9 
10     pub const Phase = enum { initialization, steady, teardown };
11 };
12 
13 pub const PhaseBoundary = struct {
14     state: ?*PhaseBoundaryState = null,
15 
16     pub fn seal(self: PhaseBoundary) void {
17         const state = self.state orelse return;
18         std.debug.assert(state.phase == .initialization);
19         policy.sealProcessAllocatorPhase();
20         state.phase = .steady;
21         state.sealed = true;
22     }
23 
24     pub fn beginTeardown(self: PhaseBoundary) void {
25         const state = self.state orelse return;
26         if (state.phase != .steady) return;
27         policy.beginProcessAllocatorTeardown();
28         state.phase = .teardown;
29     }
30 
31     pub fn sealed(self: PhaseBoundary) bool {
32         const state = self.state orelse return false;
33         return state.sealed;
34     }
35 };
36 
37 pub fn writePhaseReport(writer: *std.Io.Writer, tool: []const u8, was_sealed: bool) !bool {
38     const violations = process.violations() orelse return false;
39     try writer.print(
40         "{s} allocator phase steady violations: sealed={} total={d} alloc={d} " ++
41             "resize={d} remap={d} free={d}",
42         .{
43             tool,
44             was_sealed,
45             violations.total(),
46             violations.allocations,
47             violations.resizes,
48             violations.remaps,
49             violations.frees,
50         },
51     );
52     if (process.violationSites()) |sites| {
53         for (sites.slice()) |address| try writer.print(" site=0x{x}", .{address});
54     }
55     try writer.writeByte('\n');
56     return true;
57 }
58 
59 test "phase boundary without state is inert" {
60     const boundary = PhaseBoundary{};
61     boundary.seal();
62     boundary.beginTeardown();
63     try std.testing.expect(!boundary.sealed());
64 }
65 
66 test "phase report is silent when the phase machinery is off" {
67     if (process.mode != .off) return;
68     var buffer: [256]u8 = undefined;
69     var writer = std.Io.Writer.fixed(&buffer);
70     try std.testing.expect(!(try writePhaseReport(&writer, "test", false)));
71     try std.testing.expectEqual(@as(usize, 0), writer.buffered().len);
72 }
73 
74 test "phase boundary transitions once through steady into teardown" {
75     if (process.mode == .off) return;
76     var state = PhaseBoundaryState{};
77     const boundary = PhaseBoundary{ .state = &state };
78     if (process.currentPhase()) |phase| {
79         if (phase != .initialization) return;
80     }
81     boundary.seal();
82     try std.testing.expect(boundary.sealed());
83     try std.testing.expectEqual(PhaseBoundaryState.Phase.steady, state.phase);
84     boundary.beginTeardown();
85     try std.testing.expectEqual(PhaseBoundaryState.Phase.teardown, state.phase);
86 }