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