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 }