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