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