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