From 099a95041054e456ebefbd75f6a4f9f6961002be Mon Sep 17 00:00:00 2001 From: mlugg Date: Fri, 19 Sep 2025 13:35:12 +0100 Subject: std.debug.SelfInfo: thread safety This has been a TODO for ages, but in the past it didn't really matter because stack traces are typically printed to stderr for which a mutex is held so in practice there was a mutex guarding usage of `SelfInfo`. However, now that `SelfInfo` is also used for simply capturing traces, thread safety is needed. Instead of just a single mutex, though, there are a couple of different mutexes involved; this helps make critical sections smaller, particularly when unwinding the stack as `unwindFrame` doesn't typically need to hold any lock at all. --- lib/std/debug.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/std/debug.zig') diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 3d8bc565e7..e587ddd5c9 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -238,7 +238,6 @@ pub fn print(comptime fmt: []const u8, args: anytype) void { nosuspend bw.print(fmt, args) catch return; } -/// TODO multithreaded awareness /// Marked `inline` to propagate a comptime-known error to callers. pub inline fn getSelfDebugInfo() !*SelfInfo { if (!SelfInfo.target_supported) return error.UnsupportedTarget; @@ -1169,7 +1168,8 @@ test printLineFromFile { } } -/// TODO multithreaded awareness +/// The returned allocator should be thread-safe if the compilation is multi-threaded, because +/// multiple threads could capture and/or print stack traces simultaneously. fn getDebugInfoAllocator() Allocator { // Allow overriding the debug info allocator by exposing `root.debug.getDebugInfoAllocator`. if (@hasDecl(root, "debug") and @hasDecl(root.debug, "getDebugInfoAllocator")) { @@ -1177,10 +1177,10 @@ fn getDebugInfoAllocator() Allocator { } // Otherwise, use a global arena backed by the page allocator const S = struct { - var arena: ?std.heap.ArenaAllocator = null; + var arena: std.heap.ArenaAllocator = .init(std.heap.page_allocator); + var ts_arena: std.heap.ThreadSafeAllocator = .{ .child_allocator = arena.allocator() }; }; - if (S.arena == null) S.arena = .init(std.heap.page_allocator); - return S.arena.?.allocator(); + return S.ts_arena.allocator(); } /// Whether or not the current target can print useful debug information when a segfault occurs. -- cgit v1.2.3