aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/panic.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-04-19 07:32:34 -0700
committerIan Lance Taylor <iant@golang.org>2017-06-05 22:42:48 +0000
commit2d86f4942868c1309051062237cf4d424d588e9c (patch)
tree83daa9155317bed206497703c0132b1bfc4a0265 /src/runtime/panic.go
parent3c745d750e8342b1dd4144a83488b559efb8b271 (diff)
downloadgo-2d86f4942868c1309051062237cf4d424d588e9c.tar.xz
runtime: delay exiting while panic is running deferred functions
Try to avoid a race between the main goroutine exiting and a panic occurring. Don't try too hard, to avoid hanging. Updates #3934 Fixes #20018 Change-Id: I57a02b6d795d2a61f1cadd137ce097145280ece7 Reviewed-on: https://go-review.googlesource.com/41052 Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/panic.go')
-rw-r--r--src/runtime/panic.go21
1 files changed, 20 insertions, 1 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index f099f2292c..43bfdd7a1e 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -456,6 +456,8 @@ func gopanic(e interface{}) {
p.link = gp._panic
gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
+ atomic.Xadd(&runningPanicDefers, 1)
+
for {
d := gp._defer
if d == nil {
@@ -504,6 +506,8 @@ func gopanic(e interface{}) {
sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
freedefer(d)
if p.recovered {
+ atomic.Xadd(&runningPanicDefers, -1)
+
gp._panic = p.link
// Aborted panics are marked but remain on the g.panic list.
// Remove them from the list.
@@ -527,6 +531,11 @@ func gopanic(e interface{}) {
// and String methods to prepare the panic strings before startpanic.
preprintpanics(gp._panic)
startpanic()
+
+ // startpanic set panicking, which will block main from exiting,
+ // so now OK to decrement runningPanicDefers.
+ atomic.Xadd(&runningPanicDefers, -1)
+
printpanics(gp._panic)
dopanic(0) // should not return
*(*int)(nil) = 0 // not reached
@@ -597,7 +606,17 @@ func throw(s string) {
*(*int)(nil) = 0 // not reached
}
-//uint32 runtime·panicking;
+// runningPanicDefers is non-zero while running deferred functions for panic.
+// runningPanicDefers is incremented and decremented atomically.
+// This is used to try hard to get a panic stack trace out when exiting.
+var runningPanicDefers uint32
+
+// panicking is non-zero when crashing the program for an unrecovered panic.
+// panicking is incremented and decremented atomically.
+var panicking uint32
+
+// paniclk is held while printing the panic information and stack trace,
+// so that two concurrent panics don't overlap their output.
var paniclk mutex
// Unwind the stack after a deferred function calls recover