github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/src/runtime/signal_sighandler.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
     6  
     7  package runtime
     8  
     9  import (
    10  	"unsafe"
    11  )
    12  
    13  // crashing is the number of m's we have waited for when implementing
    14  // GOTRACEBACK=crash when a signal is received.
    15  var crashing int32
    16  
    17  // sighandler is invoked when a signal occurs. The global g will be
    18  // set to a gsignal goroutine and we will be running on the alternate
    19  // signal stack. The parameter g will be the value of the global g
    20  // when the signal occurred. The sig, info, and ctxt parameters are
    21  // from the system signal handler: they are the parameters passed when
    22  // the SA is passed to the sigaction system call.
    23  //
    24  // The garbage collector may have stopped the world, so write barriers
    25  // are not allowed.
    26  //
    27  //go:nowritebarrierrec
    28  func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
    29  	_g_ := getg()
    30  	c := &sigctxt{info, ctxt}
    31  
    32  	if sig == _SIGPROF {
    33  		sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
    34  		return
    35  	}
    36  
    37  	flags := int32(_SigThrow)
    38  	if sig < uint32(len(sigtable)) {
    39  		flags = sigtable[sig].flags
    40  	}
    41  	if flags&_SigPanic != 0 && gp.throwsplit {
    42  		// We can't safely sigpanic because it may grow the
    43  		// stack. Abort in the signal handler instead.
    44  		flags = (flags &^ _SigPanic) | _SigThrow
    45  	}
    46  	if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
    47  		// The signal is going to cause a panic.
    48  		// Arrange the stack so that it looks like the point
    49  		// where the signal occurred made a call to the
    50  		// function sigpanic. Then set the PC to sigpanic.
    51  
    52  		// Have to pass arguments out of band since
    53  		// augmenting the stack frame would break
    54  		// the unwinding code.
    55  		gp.sig = sig
    56  		gp.sigcode0 = uintptr(c.sigcode())
    57  		gp.sigcode1 = uintptr(c.fault())
    58  		gp.sigpc = c.sigpc()
    59  
    60  		c.preparePanic(sig, gp)
    61  		return
    62  	}
    63  
    64  	if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
    65  		if sigsend(sig) {
    66  			return
    67  		}
    68  	}
    69  
    70  	if c.sigcode() == _SI_USER && signal_ignored(sig) {
    71  		return
    72  	}
    73  
    74  	if flags&_SigKill != 0 {
    75  		dieFromSignal(sig)
    76  	}
    77  
    78  	if flags&_SigThrow == 0 {
    79  		return
    80  	}
    81  
    82  	_g_.m.throwing = 1
    83  	_g_.m.caughtsig.set(gp)
    84  
    85  	if crashing == 0 {
    86  		startpanic()
    87  	}
    88  
    89  	if sig < uint32(len(sigtable)) {
    90  		print(sigtable[sig].name, "\n")
    91  	} else {
    92  		print("Signal ", sig, "\n")
    93  	}
    94  
    95  	print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
    96  	if _g_.m.lockedg != 0 && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
    97  		print("signal arrived during cgo execution\n")
    98  		gp = _g_.m.lockedg.ptr()
    99  	}
   100  	print("\n")
   101  
   102  	level, _, docrash := gotraceback()
   103  	if level > 0 {
   104  		goroutineheader(gp)
   105  		tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
   106  		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
   107  			// tracebackothers on original m skipped this one; trace it now.
   108  			goroutineheader(_g_.m.curg)
   109  			traceback(^uintptr(0), ^uintptr(0), 0, _g_.m.curg)
   110  		} else if crashing == 0 {
   111  			tracebackothers(gp)
   112  			print("\n")
   113  		}
   114  		dumpregs(c)
   115  	}
   116  
   117  	if docrash {
   118  		crashing++
   119  		if crashing < mcount()-int32(extraMCount) {
   120  			// There are other m's that need to dump their stacks.
   121  			// Relay SIGQUIT to the next m by sending it to the current process.
   122  			// All m's that have already received SIGQUIT have signal masks blocking
   123  			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
   124  			// When the last m receives the SIGQUIT, it will fall through to the call to
   125  			// crash below. Just in case the relaying gets botched, each m involved in
   126  			// the relay sleeps for 5 seconds and then does the crash/exit itself.
   127  			// In expected operation, the last m has received the SIGQUIT and run
   128  			// crash/exit and the process is gone, all long before any of the
   129  			// 5-second sleeps have finished.
   130  			print("\n-----\n\n")
   131  			raiseproc(_SIGQUIT)
   132  			usleep(5 * 1000 * 1000)
   133  		}
   134  		crash()
   135  	}
   136  
   137  	exit(2)
   138  }