From 426bfbe9a375aebf5df2fbc5eb340fccc0466382 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 11 Oct 2019 09:52:11 -0700 Subject: [PATCH] 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 Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/runtime/signal_sighandler.go | 154 ------------------------------- src/runtime/signal_unix.go | 143 ++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 154 deletions(-) delete mode 100644 src/runtime/signal_sighandler.go diff --git a/src/runtime/signal_sighandler.go b/src/runtime/signal_sighandler.go deleted file mode 100644 index b81957ef02..0000000000 --- a/src/runtime/signal_sighandler.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris - -package runtime - -import ( - "unsafe" -) - -// 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) -} diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 6a8b5b7ace..a9a65d5164 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -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 -- 2.48.1