github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/runtime/signal1_unix.go (about)

     1  // Copyright 2012 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 netbsd openbsd solaris
     6  
     7  package runtime
     8  
     9  import (
    10  	"runtime/internal/sys"
    11  	"unsafe"
    12  )
    13  
    14  const (
    15  	_SIG_DFL uintptr = 0
    16  	_SIG_IGN uintptr = 1
    17  )
    18  
    19  // Stores the signal handlers registered before Go installed its own.
    20  // These signal handlers will be invoked in cases where Go doesn't want to
    21  // handle a particular signal (e.g., signal occurred on a non-Go thread).
    22  // See sigfwdgo() for more information on when the signals are forwarded.
    23  //
    24  // Signal forwarding is currently available only on Darwin and Linux.
    25  var fwdSig [_NSIG]uintptr
    26  
    27  // sigmask represents a general signal mask compatible with the GOOS
    28  // specific sigset types: the signal numbered x is represented by bit x-1
    29  // to match the representation expected by sigprocmask.
    30  type sigmask [(_NSIG + 31) / 32]uint32
    31  
    32  // channels for synchronizing signal mask updates with the signal mask
    33  // thread
    34  var (
    35  	disableSigChan  chan uint32
    36  	enableSigChan   chan uint32
    37  	maskUpdatedChan chan struct{}
    38  )
    39  
    40  func init() {
    41  	// _NSIG is the number of signals on this operating system.
    42  	// sigtable should describe what to do for all the possible signals.
    43  	if len(sigtable) != _NSIG {
    44  		print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
    45  		throw("bad sigtable len")
    46  	}
    47  }
    48  
    49  var signalsOK bool
    50  
    51  // Initialize signals.
    52  // Called by libpreinit so runtime may not be initialized.
    53  //go:nosplit
    54  //go:nowritebarrierrec
    55  func initsig(preinit bool) {
    56  	if !preinit {
    57  		// It's now OK for signal handlers to run.
    58  		signalsOK = true
    59  	}
    60  
    61  	// For c-archive/c-shared this is called by libpreinit with
    62  	// preinit == true.
    63  	if (isarchive || islibrary) && !preinit {
    64  		return
    65  	}
    66  
    67  	for i := int32(0); i < _NSIG; i++ {
    68  		t := &sigtable[i]
    69  		if t.flags == 0 || t.flags&_SigDefault != 0 {
    70  			continue
    71  		}
    72  		fwdSig[i] = getsig(i)
    73  
    74  		if !sigInstallGoHandler(i) {
    75  			// Even if we are not installing a signal handler,
    76  			// set SA_ONSTACK if necessary.
    77  			if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN {
    78  				setsigstack(i)
    79  			}
    80  			continue
    81  		}
    82  
    83  		t.flags |= _SigHandling
    84  		setsig(i, funcPC(sighandler), true)
    85  	}
    86  }
    87  
    88  //go:nosplit
    89  //go:nowritebarrierrec
    90  func sigInstallGoHandler(sig int32) bool {
    91  	// For some signals, we respect an inherited SIG_IGN handler
    92  	// rather than insist on installing our own default handler.
    93  	// Even these signals can be fetched using the os/signal package.
    94  	switch sig {
    95  	case _SIGHUP, _SIGINT:
    96  		if fwdSig[sig] == _SIG_IGN {
    97  			return false
    98  		}
    99  	}
   100  
   101  	t := &sigtable[sig]
   102  	if t.flags&_SigSetStack != 0 {
   103  		return false
   104  	}
   105  
   106  	// When built using c-archive or c-shared, only install signal
   107  	// handlers for synchronous signals.
   108  	if (isarchive || islibrary) && t.flags&_SigPanic == 0 {
   109  		return false
   110  	}
   111  
   112  	return true
   113  }
   114  
   115  func sigenable(sig uint32) {
   116  	if sig >= uint32(len(sigtable)) {
   117  		return
   118  	}
   119  
   120  	t := &sigtable[sig]
   121  	if t.flags&_SigNotify != 0 {
   122  		ensureSigM()
   123  		enableSigChan <- sig
   124  		<-maskUpdatedChan
   125  		if t.flags&_SigHandling == 0 {
   126  			t.flags |= _SigHandling
   127  			fwdSig[sig] = getsig(int32(sig))
   128  			setsig(int32(sig), funcPC(sighandler), true)
   129  		}
   130  	}
   131  }
   132  
   133  func sigdisable(sig uint32) {
   134  	if sig >= uint32(len(sigtable)) {
   135  		return
   136  	}
   137  
   138  	t := &sigtable[sig]
   139  	if t.flags&_SigNotify != 0 {
   140  		ensureSigM()
   141  		disableSigChan <- sig
   142  		<-maskUpdatedChan
   143  
   144  		// If initsig does not install a signal handler for a
   145  		// signal, then to go back to the state before Notify
   146  		// we should remove the one we installed.
   147  		if !sigInstallGoHandler(int32(sig)) {
   148  			t.flags &^= _SigHandling
   149  			setsig(int32(sig), fwdSig[sig], true)
   150  		}
   151  	}
   152  }
   153  
   154  func sigignore(sig uint32) {
   155  	if sig >= uint32(len(sigtable)) {
   156  		return
   157  	}
   158  
   159  	t := &sigtable[sig]
   160  	if t.flags&_SigNotify != 0 {
   161  		t.flags &^= _SigHandling
   162  		setsig(int32(sig), _SIG_IGN, true)
   163  	}
   164  }
   165  
   166  func resetcpuprofiler(hz int32) {
   167  	var it itimerval
   168  	if hz == 0 {
   169  		setitimer(_ITIMER_PROF, &it, nil)
   170  	} else {
   171  		it.it_interval.tv_sec = 0
   172  		it.it_interval.set_usec(1000000 / hz)
   173  		it.it_value = it.it_interval
   174  		setitimer(_ITIMER_PROF, &it, nil)
   175  	}
   176  	_g_ := getg()
   177  	_g_.m.profilehz = hz
   178  }
   179  
   180  func sigpipe() {
   181  	if sigsend(_SIGPIPE) {
   182  		return
   183  	}
   184  	dieFromSignal(_SIGPIPE)
   185  }
   186  
   187  // dieFromSignal kills the program with a signal.
   188  // This provides the expected exit status for the shell.
   189  // This is only called with fatal signals expected to kill the process.
   190  //go:nosplit
   191  //go:nowritebarrierrec
   192  func dieFromSignal(sig int32) {
   193  	setsig(sig, _SIG_DFL, false)
   194  	updatesigmask(sigmask{})
   195  	raise(sig)
   196  
   197  	// That should have killed us. On some systems, though, raise
   198  	// sends the signal to the whole process rather than to just
   199  	// the current thread, which means that the signal may not yet
   200  	// have been delivered. Give other threads a chance to run and
   201  	// pick up the signal.
   202  	osyield()
   203  	osyield()
   204  	osyield()
   205  
   206  	// If we are still somehow running, just exit with the wrong status.
   207  	exit(2)
   208  }
   209  
   210  // raisebadsignal is called when a signal is received on a non-Go
   211  // thread, and the Go program does not want to handle it (that is, the
   212  // program has not called os/signal.Notify for the signal).
   213  func raisebadsignal(sig int32, c *sigctxt) {
   214  	if sig == _SIGPROF {
   215  		// Ignore profiling signals that arrive on non-Go threads.
   216  		return
   217  	}
   218  
   219  	var handler uintptr
   220  	if sig >= _NSIG {
   221  		handler = _SIG_DFL
   222  	} else {
   223  		handler = fwdSig[sig]
   224  	}
   225  
   226  	// Reset the signal handler and raise the signal.
   227  	// We are currently running inside a signal handler, so the
   228  	// signal is blocked. We need to unblock it before raising the
   229  	// signal, or the signal we raise will be ignored until we return
   230  	// from the signal handler. We know that the signal was unblocked
   231  	// before entering the handler, or else we would not have received
   232  	// it. That means that we don't have to worry about blocking it
   233  	// again.
   234  	unblocksig(sig)
   235  	setsig(sig, handler, false)
   236  
   237  	// If we're linked into a non-Go program we want to try to
   238  	// avoid modifying the original context in which the signal
   239  	// was raised. If the handler is the default, we know it
   240  	// is non-recoverable, so we don't have to worry about
   241  	// re-installing sighandler. At this point we can just
   242  	// return and the signal will be re-raised and caught by
   243  	// the default handler with the correct context.
   244  	if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
   245  		return
   246  	}
   247  
   248  	raise(sig)
   249  
   250  	// If the signal didn't cause the program to exit, restore the
   251  	// Go signal handler and carry on.
   252  	//
   253  	// We may receive another instance of the signal before we
   254  	// restore the Go handler, but that is not so bad: we know
   255  	// that the Go program has been ignoring the signal.
   256  	setsig(sig, funcPC(sighandler), true)
   257  }
   258  
   259  func crash() {
   260  	if GOOS == "darwin" {
   261  		// OS X core dumps are linear dumps of the mapped memory,
   262  		// from the first virtual byte to the last, with zeros in the gaps.
   263  		// Because of the way we arrange the address space on 64-bit systems,
   264  		// this means the OS X core file will be >128 GB and even on a zippy
   265  		// workstation can take OS X well over an hour to write (uninterruptible).
   266  		// Save users from making that mistake.
   267  		if sys.PtrSize == 8 {
   268  			return
   269  		}
   270  	}
   271  
   272  	dieFromSignal(_SIGABRT)
   273  }
   274  
   275  // ensureSigM starts one global, sleeping thread to make sure at least one thread
   276  // is available to catch signals enabled for os/signal.
   277  func ensureSigM() {
   278  	if maskUpdatedChan != nil {
   279  		return
   280  	}
   281  	maskUpdatedChan = make(chan struct{})
   282  	disableSigChan = make(chan uint32)
   283  	enableSigChan = make(chan uint32)
   284  	go func() {
   285  		// Signal masks are per-thread, so make sure this goroutine stays on one
   286  		// thread.
   287  		LockOSThread()
   288  		defer UnlockOSThread()
   289  		// The sigBlocked mask contains the signals not active for os/signal,
   290  		// initially all signals except the essential. When signal.Notify()/Stop is called,
   291  		// sigenable/sigdisable in turn notify this thread to update its signal
   292  		// mask accordingly.
   293  		var sigBlocked sigmask
   294  		for i := range sigBlocked {
   295  			sigBlocked[i] = ^uint32(0)
   296  		}
   297  		for i := range sigtable {
   298  			if sigtable[i].flags&_SigUnblock != 0 {
   299  				sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   300  			}
   301  		}
   302  		updatesigmask(sigBlocked)
   303  		for {
   304  			select {
   305  			case sig := <-enableSigChan:
   306  				if b := sig - 1; sig > 0 {
   307  					sigBlocked[b/32] &^= (1 << (b & 31))
   308  				}
   309  			case sig := <-disableSigChan:
   310  				if b := sig - 1; sig > 0 {
   311  					sigBlocked[b/32] |= (1 << (b & 31))
   312  				}
   313  			}
   314  			updatesigmask(sigBlocked)
   315  			maskUpdatedChan <- struct{}{}
   316  		}
   317  	}()
   318  }
   319  
   320  // This is called when we receive a signal when there is no signal stack.
   321  // This can only happen if non-Go code calls sigaltstack to disable the
   322  // signal stack. This is called via cgocallback to establish a stack.
   323  func noSignalStack(sig uint32) {
   324  	println("signal", sig, "received on thread with no signal stack")
   325  	throw("non-Go code disabled sigaltstack")
   326  }
   327  
   328  // This is called if we receive a signal when there is a signal stack
   329  // but we are not on it. This can only happen if non-Go code called
   330  // sigaction without setting the SS_ONSTACK flag.
   331  func sigNotOnStack(sig uint32) {
   332  	println("signal", sig, "received but handler not on signal stack")
   333  	throw("non-Go code set up signal handler without SA_ONSTACK flag")
   334  }
   335  
   336  // This runs on a foreign stack, without an m or a g. No stack split.
   337  //go:nosplit
   338  //go:norace
   339  //go:nowritebarrierrec
   340  func badsignal(sig uintptr, c *sigctxt) {
   341  	cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)+unsafe.Sizeof(c), 0)
   342  }
   343  
   344  func badsignalgo(sig uintptr, c *sigctxt) {
   345  	if !sigsend(uint32(sig)) {
   346  		// A foreign thread received the signal sig, and the
   347  		// Go code does not want to handle it.
   348  		raisebadsignal(int32(sig), c)
   349  	}
   350  }