Home | History | Annotate | Download | only in runtime
      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 }
    242