Skip to content

Commit 426bfbe

Browse files
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 <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent df38069 commit 426bfbe

File tree

2 files changed

+143
-154
lines changed

2 files changed

+143
-154
lines changed

src/runtime/signal_sighandler.go

-154
This file was deleted.

src/runtime/signal_unix.go

+143
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,149 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
370370
}
371371
}
372372

373+
// crashing is the number of m's we have waited for when implementing
374+
// GOTRACEBACK=crash when a signal is received.
375+
var crashing int32
376+
377+
// testSigtrap is used by the runtime tests. If non-nil, it is called
378+
// on SIGTRAP. If it returns true, the normal behavior on SIGTRAP is
379+
// suppressed.
380+
var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool
381+
382+
// sighandler is invoked when a signal occurs. The global g will be
383+
// set to a gsignal goroutine and we will be running on the alternate
384+
// signal stack. The parameter g will be the value of the global g
385+
// when the signal occurred. The sig, info, and ctxt parameters are
386+
// from the system signal handler: they are the parameters passed when
387+
// the SA is passed to the sigaction system call.
388+
//
389+
// The garbage collector may have stopped the world, so write barriers
390+
// are not allowed.
391+
//
392+
//go:nowritebarrierrec
393+
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
394+
_g_ := getg()
395+
c := &sigctxt{info, ctxt}
396+
397+
if sig == _SIGPROF {
398+
sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
399+
return
400+
}
401+
402+
if sig == _SIGTRAP && testSigtrap != nil && testSigtrap(info, (*sigctxt)(noescape(unsafe.Pointer(c))), gp) {
403+
return
404+
}
405+
406+
flags := int32(_SigThrow)
407+
if sig < uint32(len(sigtable)) {
408+
flags = sigtable[sig].flags
409+
}
410+
if flags&_SigPanic != 0 && gp.throwsplit {
411+
// We can't safely sigpanic because it may grow the
412+
// stack. Abort in the signal handler instead.
413+
flags = (flags &^ _SigPanic) | _SigThrow
414+
}
415+
if isAbortPC(c.sigpc()) {
416+
// On many architectures, the abort function just
417+
// causes a memory fault. Don't turn that into a panic.
418+
flags = _SigThrow
419+
}
420+
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
421+
// The signal is going to cause a panic.
422+
// Arrange the stack so that it looks like the point
423+
// where the signal occurred made a call to the
424+
// function sigpanic. Then set the PC to sigpanic.
425+
426+
// Have to pass arguments out of band since
427+
// augmenting the stack frame would break
428+
// the unwinding code.
429+
gp.sig = sig
430+
gp.sigcode0 = uintptr(c.sigcode())
431+
gp.sigcode1 = uintptr(c.fault())
432+
gp.sigpc = c.sigpc()
433+
434+
c.preparePanic(sig, gp)
435+
return
436+
}
437+
438+
if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
439+
if sigsend(sig) {
440+
return
441+
}
442+
}
443+
444+
if c.sigcode() == _SI_USER && signal_ignored(sig) {
445+
return
446+
}
447+
448+
if flags&_SigKill != 0 {
449+
dieFromSignal(sig)
450+
}
451+
452+
if flags&_SigThrow == 0 {
453+
return
454+
}
455+
456+
_g_.m.throwing = 1
457+
_g_.m.caughtsig.set(gp)
458+
459+
if crashing == 0 {
460+
startpanic_m()
461+
}
462+
463+
if sig < uint32(len(sigtable)) {
464+
print(sigtable[sig].name, "\n")
465+
} else {
466+
print("Signal ", sig, "\n")
467+
}
468+
469+
print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
470+
if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
471+
print("signal arrived during cgo execution\n")
472+
gp = _g_.m.lockedg.ptr()
473+
}
474+
print("\n")
475+
476+
level, _, docrash := gotraceback()
477+
if level > 0 {
478+
goroutineheader(gp)
479+
tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
480+
if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
481+
// tracebackothers on original m skipped this one; trace it now.
482+
goroutineheader(_g_.m.curg)
483+
traceback(^uintptr(0), ^uintptr(0), 0, _g_.m.curg)
484+
} else if crashing == 0 {
485+
tracebackothers(gp)
486+
print("\n")
487+
}
488+
dumpregs(c)
489+
}
490+
491+
if docrash {
492+
crashing++
493+
if crashing < mcount()-int32(extraMCount) {
494+
// There are other m's that need to dump their stacks.
495+
// Relay SIGQUIT to the next m by sending it to the current process.
496+
// All m's that have already received SIGQUIT have signal masks blocking
497+
// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
498+
// When the last m receives the SIGQUIT, it will fall through to the call to
499+
// crash below. Just in case the relaying gets botched, each m involved in
500+
// the relay sleeps for 5 seconds and then does the crash/exit itself.
501+
// In expected operation, the last m has received the SIGQUIT and run
502+
// crash/exit and the process is gone, all long before any of the
503+
// 5-second sleeps have finished.
504+
print("\n-----\n\n")
505+
raiseproc(_SIGQUIT)
506+
usleep(5 * 1000 * 1000)
507+
}
508+
crash()
509+
}
510+
511+
printDebugLog()
512+
513+
exit(2)
514+
}
515+
373516
// sigpanic turns a synchronous signal into a run-time panic.
374517
// If the signal handler sees a synchronous panic, it arranges the
375518
// stack to look like the function where the signal occurred called

0 commit comments

Comments
 (0)