mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: move sighandler into signal_unix.go
We couldn't do this before because sighandler was compiled for nacl. Updates #30439 Change-Id: Ieec9938b6a1796c48d251cd8b1db1a42c25f3943 Reviewed-on: https://go-review.googlesource.com/c/go/+/200739 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
df380693f3
commit
426bfbe9a3
2 changed files with 143 additions and 154 deletions
|
|
@ -370,6 +370,149 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
|
|||
}
|
||||
}
|
||||
|
||||
// crashing is the number of m's we have waited for when implementing
|
||||
// GOTRACEBACK=crash when a signal is received.
|
||||
var crashing int32
|
||||
|
||||
// testSigtrap is used by the runtime tests. If non-nil, it is called
|
||||
// on SIGTRAP. If it returns true, the normal behavior on SIGTRAP is
|
||||
// suppressed.
|
||||
var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
|
||||
|
||||
// sighandler is invoked when a signal occurs. The global g will be
|
||||
// set to a gsignal goroutine and we will be running on the alternate
|
||||
// signal stack. The parameter g will be the value of the global g
|
||||
// when the signal occurred. The sig, info, and ctxt parameters are
|
||||
// from the system signal handler: they are the parameters passed when
|
||||
// the SA is passed to the sigaction system call.
|
||||
//
|
||||
// The garbage collector may have stopped the world, so write barriers
|
||||
// are not allowed.
|
||||
//
|
||||
//go:nowritebarrierrec
|
||||
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||
_g_ := getg()
|
||||
c := &sigctxt{info, ctxt}
|
||||
|
||||
if sig == _SIGPROF {
|
||||
sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
|
||||
return
|
||||
}
|
||||
|
||||
if sig == _SIGTRAP && testSigtrap != nil && testSigtrap(info, (*sigctxt)(noescape(unsafe.Pointer(c))), gp) {
|
||||
return
|
||||
}
|
||||
|
||||
flags := int32(_SigThrow)
|
||||
if sig < uint32(len(sigtable)) {
|
||||
flags = sigtable[sig].flags
|
||||
}
|
||||
if flags&_SigPanic != 0 && gp.throwsplit {
|
||||
// We can't safely sigpanic because it may grow the
|
||||
// stack. Abort in the signal handler instead.
|
||||
flags = (flags &^ _SigPanic) | _SigThrow
|
||||
}
|
||||
if isAbortPC(c.sigpc()) {
|
||||
// On many architectures, the abort function just
|
||||
// causes a memory fault. Don't turn that into a panic.
|
||||
flags = _SigThrow
|
||||
}
|
||||
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
|
||||
// The signal is going to cause a panic.
|
||||
// Arrange the stack so that it looks like the point
|
||||
// where the signal occurred made a call to the
|
||||
// function sigpanic. Then set the PC to sigpanic.
|
||||
|
||||
// Have to pass arguments out of band since
|
||||
// augmenting the stack frame would break
|
||||
// the unwinding code.
|
||||
gp.sig = sig
|
||||
gp.sigcode0 = uintptr(c.sigcode())
|
||||
gp.sigcode1 = uintptr(c.fault())
|
||||
gp.sigpc = c.sigpc()
|
||||
|
||||
c.preparePanic(sig, gp)
|
||||
return
|
||||
}
|
||||
|
||||
if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
|
||||
if sigsend(sig) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if c.sigcode() == _SI_USER && signal_ignored(sig) {
|
||||
return
|
||||
}
|
||||
|
||||
if flags&_SigKill != 0 {
|
||||
dieFromSignal(sig)
|
||||
}
|
||||
|
||||
if flags&_SigThrow == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
_g_.m.throwing = 1
|
||||
_g_.m.caughtsig.set(gp)
|
||||
|
||||
if crashing == 0 {
|
||||
startpanic_m()
|
||||
}
|
||||
|
||||
if sig < uint32(len(sigtable)) {
|
||||
print(sigtable[sig].name, "\n")
|
||||
} else {
|
||||
print("Signal ", sig, "\n")
|
||||
}
|
||||
|
||||
print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
|
||||
if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
|
||||
print("signal arrived during cgo execution\n")
|
||||
gp = _g_.m.lockedg.ptr()
|
||||
}
|
||||
print("\n")
|
||||
|
||||
level, _, docrash := gotraceback()
|
||||
if level > 0 {
|
||||
goroutineheader(gp)
|
||||
tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
|
||||
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, _g_.m.curg)
|
||||
} else if crashing == 0 {
|
||||
tracebackothers(gp)
|
||||
print("\n")
|
||||
}
|
||||
dumpregs(c)
|
||||
}
|
||||
|
||||
if docrash {
|
||||
crashing++
|
||||
if crashing < mcount()-int32(extraMCount) {
|
||||
// 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()
|
||||
}
|
||||
|
||||
printDebugLog()
|
||||
|
||||
exit(2)
|
||||
}
|
||||
|
||||
// sigpanic turns a synchronous signal into a run-time panic.
|
||||
// If the signal handler sees a synchronous panic, it arranges the
|
||||
// stack to look like the function where the signal occurred called
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue