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
signaturelock-open 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 {
235235 panicExtra(null, first_trace_addr, format, args);
236236}
237237
238/// TODO multithreaded awareness
238/// Non-zero whenever the program triggered a panic.
239/// The counter is incremented/decremented atomically.
239240var 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
241249pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: var) noreturn {
242250 @setCold(true);
243251
......@@ -247,25 +255,50 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
247255 resetSegfaultHandler();
248256 }
249257
250 switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) {
258 switch (panic_stage) {
251259 0 => {
252 const stderr = getStderrStream();
253 noasync stderr.print(format ++ "\n", args) catch os.abort();
254 if (trace) |t| {
255 dumpStackTrace(t.*);
260 panic_stage = 1;
261
262 _ = @atomicRmw(u8, &panicking, .Add, 1, .SeqCst);
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;
256286 }
257 dumpCurrentStackTrace(first_trace_addr);
258287 },
259288 1 => {
260 // TODO detect if a different thread caused the panic, because in that case
261 // we would want to return here instead of calling abort, so that the thread
262 // which first called panic can finish printing a stack trace.
263 warn("Panicked during a panic. Aborting.\n", .{});
289 panic_stage = 2;
290
291 // A panic happened while trying to print a previous panic message,
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();
264296 },
265297 else => {
266298 // Panicked while printing "Panicked during a panic."
267299 },
268300 }
301
269302 os.abort();
270303}
271304