diff options
| author | Ian Lance Taylor <iant@golang.org> | 2017-04-19 07:32:34 -0700 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2017-06-05 22:42:48 +0000 |
| commit | 2d86f4942868c1309051062237cf4d424d588e9c (patch) | |
| tree | 83daa9155317bed206497703c0132b1bfc4a0265 /src/runtime/panic.go | |
| parent | 3c745d750e8342b1dd4144a83488b559efb8b271 (diff) | |
| download | go-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.go | 21 |
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 |
