mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: let the fault thread to crash the process
Let the fault thread to crash the program to make sure while gdb coredump file could see the correct backtrace in the number one thread in gdb.
Fixes #63277.
Change-Id: Ie4473f76f0feba596091433918bcd35a4ff7e11b
GitHub-Last-Rev: f4615c23f6
GitHub-Pull-Request: golang/go#63666
Reviewed-on: https://go-review.googlesource.com/c/go/+/536895
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
58bfef82fc
commit
de5b418bea
2 changed files with 206 additions and 47 deletions
|
|
@ -597,7 +597,7 @@ func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
|
|||
|
||||
// crashing is the number of m's we have waited for when implementing
|
||||
// GOTRACEBACK=crash when a signal is received.
|
||||
var crashing int32
|
||||
var crashing atomic.Int32
|
||||
|
||||
// testSigtrap and testSigusr1 are used by the runtime tests. If
|
||||
// non-nil, it is called on SIGTRAP/SIGUSR1. If it returns true, the
|
||||
|
|
@ -730,7 +730,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
|||
mp.throwing = throwTypeRuntime
|
||||
mp.caughtsig.set(gp)
|
||||
|
||||
if crashing == 0 {
|
||||
if crashing.Load() == 0 {
|
||||
startpanic_m()
|
||||
}
|
||||
|
||||
|
|
@ -740,11 +740,11 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
|||
if level > 0 {
|
||||
goroutineheader(gp)
|
||||
tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
|
||||
if crashing > 0 && gp != mp.curg && mp.curg != nil && readgstatus(mp.curg)&^_Gscan == _Grunning {
|
||||
if crashing.Load() > 0 && gp != mp.curg && mp.curg != nil && readgstatus(mp.curg)&^_Gscan == _Grunning {
|
||||
// tracebackothers on original m skipped this one; trace it now.
|
||||
goroutineheader(mp.curg)
|
||||
traceback(^uintptr(0), ^uintptr(0), 0, mp.curg)
|
||||
} else if crashing == 0 {
|
||||
} else if crashing.Load() == 0 {
|
||||
tracebackothers(gp)
|
||||
print("\n")
|
||||
}
|
||||
|
|
@ -752,20 +752,35 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
|||
}
|
||||
|
||||
if docrash {
|
||||
crashing++
|
||||
if crashing < mcount()-int32(extraMLength.Load()) {
|
||||
isCrashThread := false
|
||||
if crashing.CompareAndSwap(0, 1) {
|
||||
isCrashThread = true
|
||||
} else {
|
||||
crashing.Add(1)
|
||||
}
|
||||
if crashing.Load() < mcount()-int32(extraMLength.Load()) {
|
||||
// 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 first m will wait until all ms received the SIGQUIT, then crash/exit.
|
||||
// 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.
|
||||
// The faulting m is crashing first so it is the faulting thread in the core dump (see issue #63277):
|
||||
// in expected operation, the first m will wait until the last m has received the SIGQUIT,
|
||||
// and then run crash/exit and the process is gone.
|
||||
// However, if it spends more than 5 seconds to send SIGQUIT to all ms,
|
||||
// any of ms may crash/exit the process after waiting for 5 seconds.
|
||||
print("\n-----\n\n")
|
||||
raiseproc(_SIGQUIT)
|
||||
}
|
||||
if isCrashThread {
|
||||
i := 0
|
||||
for (crashing.Load() < mcount()-int32(extraMLength.Load())) && i < 10 {
|
||||
i++
|
||||
usleep(500 * 1000)
|
||||
}
|
||||
} else {
|
||||
usleep(5 * 1000 * 1000)
|
||||
}
|
||||
printDebugLog()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue