authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-20 13:02:19-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-20 13:02:19-04:00
logef69e4efa07af12172e6dfd7aa62961f1a5491f9
treefb85bb9c07bb4fcd035f62bb36990a487499fd02
parent245dc9d930a4f11a7ce719d3b9aa272a6a1127ff
parent2501e80500f99c1ede6daf2f7c50c2dec3c9675c
signature Commit is signed but in an unrecognized format.

Merge branch 'mt-panic' of https://github.com/LemonBoy/zig into glibc-add-ld


1 files changed, 44 insertions(+), 11 deletions(-)

lib/std/debug.zig+44-11
...@@ -235,9 +235,17 @@ pub fn panic(comptime format: []const u8, args: var) noreturn {...@@ -235,9 +235,17 @@ pub fn panic(comptime format: []const u8, args: var) noreturn {
235 panicExtra(null, first_trace_addr, format, args);235 panicExtra(null, first_trace_addr, format, args);
236}236}
237237
238/// TODO multithreaded awareness238/// Non-zero whenever the program triggered a panic.
239/// The counter is incremented/decremented atomically.
239var panicking: u8 = 0;240var panicking: u8 = 0;
240241
242// Locked to avoid interleaving panic messages from multiple threads.
243var panic_mutex = std.Mutex.init();
244
245/// Counts how many times the panic handler is invoked by this thread.
246/// This is used to catch and handle panics triggered by the panic handler.
247threadlocal var panic_stage: usize = 0;
248
241pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: var) noreturn {249pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: var) noreturn {
242 @setCold(true);250 @setCold(true);
243251
...@@ -247,25 +255,50 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c...@@ -247,25 +255,50 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
247 resetSegfaultHandler();255 resetSegfaultHandler();
248 }256 }
249257
250 switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) {258 switch (panic_stage) {
251 0 => {259 0 => {
252 const stderr = getStderrStream();260 panic_stage = 1;
253 noasync stderr.print(format ++ "\n", args) catch os.abort();261
254 if (trace) |t| {262 _ = @atomicRmw(u8, &panicking, .Add, 1, .SeqCst);
255 dumpStackTrace(t.*);263
264 // Make sure to release the mutex when done
265 {
266 const held = panic_mutex.acquire();
267 defer held.release();
268
269 const stderr = getStderrStream();
270 noasync stderr.print(format ++ "\n", args) catch os.abort();
271 if (trace) |t| {
272 dumpStackTrace(t.*);
273 }
274 dumpCurrentStackTrace(first_trace_addr);
275 }
276
277 if (@atomicRmw(u8, &panicking, .Sub, 1, .SeqCst) != 1) {
278 // Another thread is panicking, wait for the last one to finish
279 // and call abort()
280
281 // Sleep forever without hammering the CPU
282 var event = std.ResetEvent.init();
283 event.wait();
284
285 unreachable;
256 }286 }
257 dumpCurrentStackTrace(first_trace_addr);
258 },287 },
259 1 => {288 1 => {
260 // TODO detect if a different thread caused the panic, because in that case289 panic_stage = 2;
261 // we would want to return here instead of calling abort, so that the thread290
262 // which first called panic can finish printing a stack trace.291 // A panic happened while trying to print a previous panic message,
263 warn("Panicked during a panic. Aborting.\n", .{});292 // we're still holding the mutex but that's fine as we're going to
293 // call abort()
294 const stderr = getStderrStream();
295 noasync stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort();
264 },296 },
265 else => {297 else => {
266 // Panicked while printing "Panicked during a panic."298 // Panicked while printing "Panicked during a panic."
267 },299 },
268 }300 }
301
269 os.abort();302 os.abort();
270}303}
271304