aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/signal_arm64.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2015-07-24 16:16:39 -0700
committerIan Lance Taylor <iant@golang.org>2015-07-27 16:58:53 +0000
commitf0876a1a940b67b3f6029dfd0b6a06348792dc04 (patch)
treeffb63478297c852a1e7c55e95b204cbaa7b6f0dc /src/runtime/signal_arm64.go
parenta2cf0568e853a22a50110e43d5185a096f3145c6 (diff)
downloadgo-f0876a1a940b67b3f6029dfd0b6a06348792dc04.tar.gz
go-f0876a1a940b67b3f6029dfd0b6a06348792dc04.zip
runtime: log all thread stack traces during GODEBUG=crash on Unix
This extends https://golang.org/cl/2811, which only applied to Darwin and GNU/Linux, to all Unix systems. Fixes #9591. Change-Id: Iec3fb438564ba2924b15b447c0480f87c0bfd009 Reviewed-on: https://go-review.googlesource.com/12661 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/runtime/signal_arm64.go')
-rw-r--r--src/runtime/signal_arm64.go35
1 files changed, 31 insertions, 4 deletions
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
index 07ab638c26..4a7c8b980b 100644
--- a/src/runtime/signal_arm64.go
+++ b/src/runtime/signal_arm64.go
@@ -45,6 +45,8 @@ func dumpregs(c *sigctxt) {
print("fault ", hex(c.fault()), "\n")
}
+var crashing int32
+
// May run during STW, so write barriers are not allowed.
//go:nowritebarrier
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
@@ -119,7 +121,10 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
_g_.m.throwing = 1
_g_.m.caughtsig.set(gp)
- startpanic()
+
+ if crashing == 0 {
+ startpanic()
+ }
if sig < uint32(len(sigtable)) {
print(sigtable[sig].name, "\n")
@@ -127,7 +132,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
print("Signal ", sig, "\n")
}
- print("PC=", hex(c.pc()), "\n")
+ print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
print("signal arrived during cgo execution\n")
gp = _g_.m.lockedg
@@ -138,12 +143,34 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
if gotraceback(&docrash) > 0 {
goroutineheader(gp)
tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp)
- tracebackothers(gp)
- print("\n")
+ if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+ // tracebackothers on original m skipped this one; trace it now.
+ goroutineheader(_g_.m.curg)
+ traceback(^uintptr(0), ^uintptr(0), 0, gp)
+ } else if crashing == 0 {
+ tracebackothers(gp)
+ print("\n")
+ }
dumpregs(c)
}
if docrash {
+ crashing++
+ if crashing < sched.mcount {
+ // There are other m's that need to dump their stacks.
+ // Relay SIGQUIT to the next m by sending it to the current process.
+ // All m's that have already received SIGQUIT have signal masks blocking
+ // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+ // When the last m receives the SIGQUIT, it will fall through to the call to
+ // crash below. Just in case the relaying gets botched, each m involved in
+ // the relay sleeps for 5 seconds and then does the crash/exit itself.
+ // In expected operation, the last m has received the SIGQUIT and run
+ // crash/exit and the process is gone, all long before any of the
+ // 5-second sleeps have finished.
+ print("\n-----\n\n")
+ raiseproc(_SIGQUIT)
+ usleep(5 * 1000 * 1000)
+ }
crash()
}