github.com/aloncn/graphics-go@v0.0.1/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 init() { 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("bad sigtable len") 43 } 44 } 45 46 var signalsOK bool 47 48 // Initialize signals. 49 // Called by libpreinit so runtime may not be initialized. 50 //go:nosplit 51 //go:nowritebarrierrec 52 func initsig(preinit bool) { 53 if !preinit { 54 // It's now OK for signal handlers to run. 55 signalsOK = true 56 } 57 58 // For c-archive/c-shared this is called by libpreinit with 59 // preinit == true. 60 if (isarchive || islibrary) && !preinit { 61 return 62 } 63 64 for i := int32(0); i < _NSIG; i++ { 65 t := &sigtable[i] 66 if t.flags == 0 || t.flags&_SigDefault != 0 { 67 continue 68 } 69 fwdSig[i] = getsig(i) 70 71 if !sigInstallGoHandler(i) { 72 // Even if we are not installing a signal handler, 73 // set SA_ONSTACK if necessary. 74 if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN { 75 setsigstack(i) 76 } 77 continue 78 } 79 80 t.flags |= _SigHandling 81 setsig(i, funcPC(sighandler), true) 82 } 83 } 84 85 //go:nosplit 86 //go:nowritebarrierrec 87 func sigInstallGoHandler(sig int32) bool { 88 // For some signals, we respect an inherited SIG_IGN handler 89 // rather than insist on installing our own default handler. 90 // Even these signals can be fetched using the os/signal package. 91 switch sig { 92 case _SIGHUP, _SIGINT: 93 if fwdSig[sig] == _SIG_IGN { 94 return false 95 } 96 } 97 98 t := &sigtable[sig] 99 if t.flags&_SigSetStack != 0 { 100 return false 101 } 102 103 // When built using c-archive or c-shared, only install signal 104 // handlers for synchronous signals. 105 if (isarchive || islibrary) && t.flags&_SigPanic == 0 { 106 return false 107 } 108 109 return true 110 } 111 112 func sigenable(sig uint32) { 113 if sig >= uint32(len(sigtable)) { 114 return 115 } 116 117 t := &sigtable[sig] 118 if t.flags&_SigNotify != 0 { 119 ensureSigM() 120 enableSigChan <- sig 121 <-maskUpdatedChan 122 if t.flags&_SigHandling == 0 { 123 t.flags |= _SigHandling 124 fwdSig[sig] = getsig(int32(sig)) 125 setsig(int32(sig), funcPC(sighandler), true) 126 } 127 } 128 } 129 130 func sigdisable(sig uint32) { 131 if sig >= uint32(len(sigtable)) { 132 return 133 } 134 135 t := &sigtable[sig] 136 if t.flags&_SigNotify != 0 { 137 ensureSigM() 138 disableSigChan <- sig 139 <-maskUpdatedChan 140 141 // If initsig does not install a signal handler for a 142 // signal, then to go back to the state before Notify 143 // we should remove the one we installed. 144 if !sigInstallGoHandler(int32(sig)) { 145 t.flags &^= _SigHandling 146 setsig(int32(sig), fwdSig[sig], true) 147 } 148 } 149 } 150 151 func sigignore(sig uint32) { 152 if sig >= uint32(len(sigtable)) { 153 return 154 } 155 156 t := &sigtable[sig] 157 if t.flags&_SigNotify != 0 { 158 t.flags &^= _SigHandling 159 setsig(int32(sig), _SIG_IGN, true) 160 } 161 } 162 163 func resetcpuprofiler(hz int32) { 164 var it itimerval 165 if hz == 0 { 166 setitimer(_ITIMER_PROF, &it, nil) 167 } else { 168 it.it_interval.tv_sec = 0 169 it.it_interval.set_usec(1000000 / hz) 170 it.it_value = it.it_interval 171 setitimer(_ITIMER_PROF, &it, nil) 172 } 173 _g_ := getg() 174 _g_.m.profilehz = hz 175 } 176 177 func sigpipe() { 178 if sigsend(_SIGPIPE) { 179 return 180 } 181 dieFromSignal(_SIGPIPE) 182 } 183 184 // dieFromSignal kills the program with a signal. 185 // This provides the expected exit status for the shell. 186 // This is only called with fatal signals expected to kill the process. 187 //go:nosplit 188 //go:nowritebarrierrec 189 func dieFromSignal(sig int32) { 190 setsig(sig, _SIG_DFL, false) 191 updatesigmask(sigmask{}) 192 raise(sig) 193 // That should have killed us; call exit just in case. 194 exit(2) 195 } 196 197 // raisebadsignal is called when a signal is received on a non-Go 198 // thread, and the Go program does not want to handle it (that is, the 199 // program has not called os/signal.Notify for the signal). 200 func raisebadsignal(sig int32) { 201 if sig == _SIGPROF { 202 // Ignore profiling signals that arrive on non-Go threads. 203 return 204 } 205 206 var handler uintptr 207 if sig >= _NSIG { 208 handler = _SIG_DFL 209 } else { 210 handler = fwdSig[sig] 211 } 212 213 // Reset the signal handler and raise the signal. 214 // We are currently running inside a signal handler, so the 215 // signal is blocked. We need to unblock it before raising the 216 // signal, or the signal we raise will be ignored until we return 217 // from the signal handler. We know that the signal was unblocked 218 // before entering the handler, or else we would not have received 219 // it. That means that we don't have to worry about blocking it 220 // again. 221 unblocksig(sig) 222 setsig(sig, handler, false) 223 raise(sig) 224 225 // If the signal didn't cause the program to exit, restore the 226 // Go signal handler and carry on. 227 // 228 // We may receive another instance of the signal before we 229 // restore the Go handler, but that is not so bad: we know 230 // that the Go program has been ignoring the signal. 231 setsig(sig, funcPC(sighandler), true) 232 } 233 234 func crash() { 235 if GOOS == "darwin" { 236 // OS X core dumps are linear dumps of the mapped memory, 237 // from the first virtual byte to the last, with zeros in the gaps. 238 // Because of the way we arrange the address space on 64-bit systems, 239 // this means the OS X core file will be >128 GB and even on a zippy 240 // workstation can take OS X well over an hour to write (uninterruptible). 241 // Save users from making that mistake. 242 if sys.PtrSize == 8 { 243 return 244 } 245 } 246 247 dieFromSignal(_SIGABRT) 248 } 249 250 // ensureSigM starts one global, sleeping thread to make sure at least one thread 251 // is available to catch signals enabled for os/signal. 252 func ensureSigM() { 253 if maskUpdatedChan != nil { 254 return 255 } 256 maskUpdatedChan = make(chan struct{}) 257 disableSigChan = make(chan uint32) 258 enableSigChan = make(chan uint32) 259 go func() { 260 // Signal masks are per-thread, so make sure this goroutine stays on one 261 // thread. 262 LockOSThread() 263 defer UnlockOSThread() 264 // The sigBlocked mask contains the signals not active for os/signal, 265 // initially all signals except the essential. When signal.Notify()/Stop is called, 266 // sigenable/sigdisable in turn notify this thread to update its signal 267 // mask accordingly. 268 var sigBlocked sigmask 269 for i := range sigBlocked { 270 sigBlocked[i] = ^uint32(0) 271 } 272 for i := range sigtable { 273 if sigtable[i].flags&_SigUnblock != 0 { 274 sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31) 275 } 276 } 277 updatesigmask(sigBlocked) 278 for { 279 select { 280 case sig := <-enableSigChan: 281 if b := sig - 1; sig > 0 { 282 sigBlocked[b/32] &^= (1 << (b & 31)) 283 } 284 case sig := <-disableSigChan: 285 if b := sig - 1; sig > 0 { 286 sigBlocked[b/32] |= (1 << (b & 31)) 287 } 288 } 289 updatesigmask(sigBlocked) 290 maskUpdatedChan <- struct{}{} 291 } 292 }() 293 } 294 295 // This is called when we receive a signal when there is no signal stack. 296 // This can only happen if non-Go code calls sigaltstack to disable the 297 // signal stack. This is called via cgocallback to establish a stack. 298 func noSignalStack(sig uint32) { 299 println("signal", sig, "received on thread with no signal stack") 300 throw("non-Go code disabled sigaltstack") 301 } 302 303 // This is called if we receive a signal when there is a signal stack 304 // but we are not on it. This can only happen if non-Go code called 305 // sigaction without setting the SS_ONSTACK flag. 306 func sigNotOnStack(sig uint32) { 307 println("signal", sig, "received but handler not on signal stack") 308 throw("non-Go code set up signal handler without SA_ONSTACK flag") 309 }