github.com/alash3al/go@v0.0.0-20150827002835-d497eeb00540/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  const (
    10  	_SIG_DFL uintptr = 0
    11  	_SIG_IGN uintptr = 1
    12  )
    13  
    14  // Stores the signal handlers registered before Go installed its own.
    15  // These signal handlers will be invoked in cases where Go doesn't want to
    16  // handle a particular signal (e.g., signal occurred on a non-Go thread).
    17  // See sigfwdgo() for more information on when the signals are forwarded.
    18  //
    19  // Signal forwarding is currently available only on Linux.
    20  var fwdSig [_NSIG]uintptr
    21  
    22  // sigmask represents a general signal mask compatible with the GOOS
    23  // specific sigset types: the signal numbered x is represented by bit x-1
    24  // to match the representation expected by sigprocmask.
    25  type sigmask [(_NSIG + 31) / 32]uint32
    26  
    27  // channels for synchronizing signal mask updates with the signal mask
    28  // thread
    29  var (
    30  	disableSigChan  chan uint32
    31  	enableSigChan   chan uint32
    32  	maskUpdatedChan chan struct{}
    33  )
    34  
    35  func initsig() {
    36  	// _NSIG is the number of signals on this operating system.
    37  	// sigtable should describe what to do for all the possible signals.
    38  	if len(sigtable) != _NSIG {
    39  		print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
    40  		throw("initsig")
    41  	}
    42  
    43  	// First call: basic setup.
    44  	for i := int32(0); i < _NSIG; i++ {
    45  		t := &sigtable[i]
    46  		if t.flags == 0 || t.flags&_SigDefault != 0 {
    47  			continue
    48  		}
    49  		fwdSig[i] = getsig(i)
    50  		// For some signals, we respect an inherited SIG_IGN handler
    51  		// rather than insist on installing our own default handler.
    52  		// Even these signals can be fetched using the os/signal package.
    53  		switch i {
    54  		case _SIGHUP, _SIGINT:
    55  			if getsig(i) == _SIG_IGN {
    56  				t.flags = _SigNotify | _SigIgnored
    57  				continue
    58  			}
    59  		}
    60  
    61  		if t.flags&_SigSetStack != 0 {
    62  			setsigstack(i)
    63  			continue
    64  		}
    65  
    66  		t.flags |= _SigHandling
    67  		setsig(i, funcPC(sighandler), true)
    68  	}
    69  }
    70  
    71  func sigenable(sig uint32) {
    72  	if sig >= uint32(len(sigtable)) {
    73  		return
    74  	}
    75  
    76  	t := &sigtable[sig]
    77  	if t.flags&_SigNotify != 0 {
    78  		ensureSigM()
    79  		enableSigChan <- sig
    80  		<-maskUpdatedChan
    81  		if t.flags&_SigHandling == 0 {
    82  			t.flags |= _SigHandling
    83  			if getsig(int32(sig)) == _SIG_IGN {
    84  				t.flags |= _SigIgnored
    85  			}
    86  			setsig(int32(sig), funcPC(sighandler), true)
    87  		}
    88  	}
    89  }
    90  
    91  func sigdisable(sig uint32) {
    92  	if sig >= uint32(len(sigtable)) {
    93  		return
    94  	}
    95  
    96  	t := &sigtable[sig]
    97  	if t.flags&_SigNotify != 0 {
    98  		ensureSigM()
    99  		disableSigChan <- sig
   100  		<-maskUpdatedChan
   101  		if t.flags&_SigHandling != 0 {
   102  			t.flags &^= _SigHandling
   103  			if t.flags&_SigIgnored != 0 {
   104  				setsig(int32(sig), _SIG_IGN, true)
   105  			} else {
   106  				setsig(int32(sig), _SIG_DFL, true)
   107  			}
   108  		}
   109  	}
   110  }
   111  
   112  func sigignore(sig uint32) {
   113  	if sig >= uint32(len(sigtable)) {
   114  		return
   115  	}
   116  
   117  	t := &sigtable[sig]
   118  	if t.flags&_SigNotify != 0 {
   119  		t.flags &^= _SigHandling
   120  		setsig(int32(sig), _SIG_IGN, true)
   121  	}
   122  }
   123  
   124  func resetcpuprofiler(hz int32) {
   125  	var it itimerval
   126  	if hz == 0 {
   127  		setitimer(_ITIMER_PROF, &it, nil)
   128  	} else {
   129  		it.it_interval.tv_sec = 0
   130  		it.it_interval.set_usec(1000000 / hz)
   131  		it.it_value = it.it_interval
   132  		setitimer(_ITIMER_PROF, &it, nil)
   133  	}
   134  	_g_ := getg()
   135  	_g_.m.profilehz = hz
   136  }
   137  
   138  func sigpipe() {
   139  	setsig(_SIGPIPE, _SIG_DFL, false)
   140  	raise(_SIGPIPE)
   141  }
   142  
   143  // raisebadsignal is called when a signal is received on a non-Go
   144  // thread, and the Go program does not want to handle it (that is, the
   145  // program has not called os/signal.Notify for the signal).
   146  func raisebadsignal(sig int32) {
   147  	if sig == _SIGPROF {
   148  		// Ignore profiling signals that arrive on non-Go threads.
   149  		return
   150  	}
   151  
   152  	var handler uintptr
   153  	if sig >= _NSIG {
   154  		handler = _SIG_DFL
   155  	} else {
   156  		handler = fwdSig[sig]
   157  	}
   158  
   159  	// Reset the signal handler and raise the signal.
   160  	// We are currently running inside a signal handler, so the
   161  	// signal is blocked.  We need to unblock it before raising the
   162  	// signal, or the signal we raise will be ignored until we return
   163  	// from the signal handler.  We know that the signal was unblocked
   164  	// before entering the handler, or else we would not have received
   165  	// it.  That means that we don't have to worry about blocking it
   166  	// again.
   167  	unblocksig(sig)
   168  	setsig(sig, handler, false)
   169  	raise(sig)
   170  
   171  	// If the signal didn't cause the program to exit, restore the
   172  	// Go signal handler and carry on.
   173  	//
   174  	// We may receive another instance of the signal before we
   175  	// restore the Go handler, but that is not so bad: we know
   176  	// that the Go program has been ignoring the signal.
   177  	setsig(sig, funcPC(sighandler), true)
   178  }
   179  
   180  func crash() {
   181  	if GOOS == "darwin" {
   182  		// OS X core dumps are linear dumps of the mapped memory,
   183  		// from the first virtual byte to the last, with zeros in the gaps.
   184  		// Because of the way we arrange the address space on 64-bit systems,
   185  		// this means the OS X core file will be >128 GB and even on a zippy
   186  		// workstation can take OS X well over an hour to write (uninterruptible).
   187  		// Save users from making that mistake.
   188  		if ptrSize == 8 {
   189  			return
   190  		}
   191  	}
   192  
   193  	updatesigmask(sigmask{})
   194  	setsig(_SIGABRT, _SIG_DFL, false)
   195  	raise(_SIGABRT)
   196  }
   197  
   198  // createSigM starts one global, sleeping thread to make sure at least one thread
   199  // is available to catch signals enabled for os/signal.
   200  func ensureSigM() {
   201  	if maskUpdatedChan != nil {
   202  		return
   203  	}
   204  	maskUpdatedChan = make(chan struct{})
   205  	disableSigChan = make(chan uint32)
   206  	enableSigChan = make(chan uint32)
   207  	go func() {
   208  		// Signal masks are per-thread, so make sure this goroutine stays on one
   209  		// thread.
   210  		LockOSThread()
   211  		defer UnlockOSThread()
   212  		// The sigBlocked mask contains the signals not active for os/signal,
   213  		// initially all signals except the essential. When signal.Notify()/Stop is called,
   214  		// sigenable/sigdisable in turn notify this thread to update its signal
   215  		// mask accordingly.
   216  		var sigBlocked sigmask
   217  		for i := range sigBlocked {
   218  			sigBlocked[i] = ^uint32(0)
   219  		}
   220  		for i := range sigtable {
   221  			if sigtable[i].flags&_SigUnblock != 0 {
   222  				sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
   223  			}
   224  		}
   225  		updatesigmask(sigBlocked)
   226  		for {
   227  			select {
   228  			case sig := <-enableSigChan:
   229  				if b := sig - 1; b >= 0 {
   230  					sigBlocked[b/32] &^= (1 << (b & 31))
   231  				}
   232  			case sig := <-disableSigChan:
   233  				if b := sig - 1; b >= 0 {
   234  					sigBlocked[b/32] |= (1 << (b & 31))
   235  				}
   236  			}
   237  			updatesigmask(sigBlocked)
   238  			maskUpdatedChan <- struct{}{}
   239  		}
   240  	}()
   241  }