aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-03-20 15:48:57 -0400
committerAndrew Kelley <andrew@ziglang.org>2020-03-20 15:48:57 -0400
commit8429ddecf89bf0e78b2e0143e9a4a6e7ba88a0fb (patch)
tree45c97bea61dd454347202e7371fa1d42d4b60938 /lib/std/debug.zig
parent541e763010403d8233a6420756a1e8393f1dd4c2 (diff)
parent7438d0fc31f70b3a6d19e1da9a4e3f7918fc9d66 (diff)
downloadzig-8429ddecf89bf0e78b2e0143e9a4a6e7ba88a0fb.tar.gz
zig-8429ddecf89bf0e78b2e0143e9a4a6e7ba88a0fb.zip
Merge branch 'glibc-add-ld'
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig55
1 files changed, 44 insertions, 11 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 0a7a0dee7e..5600990924 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -235,9 +235,17 @@ pub fn panic(comptime format: []const u8, args: var) noreturn {
panicExtra(null, first_trace_addr, format, args);
}
-/// TODO multithreaded awareness
+/// Non-zero whenever the program triggered a panic.
+/// The counter is incremented/decremented atomically.
var panicking: u8 = 0;
+// Locked to avoid interleaving panic messages from multiple threads.
+var panic_mutex = std.Mutex.init();
+
+/// Counts how many times the panic handler is invoked by this thread.
+/// This is used to catch and handle panics triggered by the panic handler.
+threadlocal var panic_stage: usize = 0;
+
pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: var) noreturn {
@setCold(true);
@@ -247,25 +255,50 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
resetSegfaultHandler();
}
- switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) {
+ switch (panic_stage) {
0 => {
- const stderr = getStderrStream();
- noasync stderr.print(format ++ "\n", args) catch os.abort();
- if (trace) |t| {
- dumpStackTrace(t.*);
+ panic_stage = 1;
+
+ _ = @atomicRmw(u8, &panicking, .Add, 1, .SeqCst);
+
+ // Make sure to release the mutex when done
+ {
+ const held = panic_mutex.acquire();
+ defer held.release();
+
+ const stderr = getStderrStream();
+ noasync stderr.print(format ++ "\n", args) catch os.abort();
+ if (trace) |t| {
+ dumpStackTrace(t.*);
+ }
+ dumpCurrentStackTrace(first_trace_addr);
+ }
+
+ if (@atomicRmw(u8, &panicking, .Sub, 1, .SeqCst) != 1) {
+ // Another thread is panicking, wait for the last one to finish
+ // and call abort()
+
+ // Sleep forever without hammering the CPU
+ var event = std.ResetEvent.init();
+ event.wait();
+
+ unreachable;
}
- dumpCurrentStackTrace(first_trace_addr);
},
1 => {
- // TODO detect if a different thread caused the panic, because in that case
- // we would want to return here instead of calling abort, so that the thread
- // which first called panic can finish printing a stack trace.
- warn("Panicked during a panic. Aborting.\n", .{});
+ panic_stage = 2;
+
+ // A panic happened while trying to print a previous panic message,
+ // we're still holding the mutex but that's fine as we're going to
+ // call abort()
+ const stderr = getStderrStream();
+ noasync stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort();
},
else => {
// Panicked while printing "Panicked during a panic."
},
}
+
os.abort();
}