Source file src/runtime/sigqueue.go
1 // Copyright 2009 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 // This file implements runtime support for signal handling. 6 // 7 // Most synchronization primitives are not available from 8 // the signal handler (it cannot block, allocate memory, or use locks) 9 // so the handler communicates with a processing goroutine 10 // via struct sig, below. 11 // 12 // sigsend is called by the signal handler to queue a new signal. 13 // signal_recv is called by the Go program to receive a newly queued signal. 14 // 15 // Synchronization between sigsend and signal_recv is based on the sig.state 16 // variable. It can be in three states: 17 // * sigReceiving means that signal_recv is blocked on sig.Note and there are 18 // no new pending signals. 19 // * sigSending means that sig.mask *may* contain new pending signals, 20 // signal_recv can't be blocked in this state. 21 // * sigIdle means that there are no new pending signals and signal_recv is not 22 // blocked. 23 // 24 // Transitions between states are done atomically with CAS. 25 // 26 // When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask. 27 // If several sigsends and signal_recv execute concurrently, it can lead to 28 // unnecessary rechecks of sig.mask, but it cannot lead to missed signals 29 // nor deadlocks. 30 31 //go:build !plan9 32 33 package runtime 34 35 import ( 36 "internal/runtime/atomic" 37 _ "unsafe" // for go:linkname 38 ) 39 40 // sig handles communication between the signal handler and os/signal. 41 // Other than the inuse and recv fields, the fields are accessed atomically. 42 // 43 // The wanted and ignored fields are only written by one goroutine at 44 // a time; access is controlled by the handlers Mutex in os/signal. 45 // The fields are only read by that one goroutine and by the signal handler. 46 // We access them atomically to minimize the race between setting them 47 // in the goroutine calling os/signal and the signal handler, 48 // which may be running in a different thread. That race is unavoidable, 49 // as there is no connection between handling a signal and receiving one, 50 // but atomic instructions should minimize it. 51 var sig struct { 52 note note 53 mask [(_NSIG + 31) / 32]uint32 54 wanted [(_NSIG + 31) / 32]uint32 55 ignored [(_NSIG + 31) / 32]uint32 56 recv [(_NSIG + 31) / 32]uint32 57 state atomic.Uint32 58 delivering atomic.Uint32 59 inuse bool 60 } 61 62 const ( 63 sigIdle = iota 64 sigReceiving 65 sigSending 66 ) 67 68 // sigsend delivers a signal from sighandler to the internal signal delivery queue. 69 // It reports whether the signal was sent. If not, the caller typically crashes the program. 70 // It runs from the signal handler, so it's limited in what it can do. 71 func sigsend(s uint32) bool { 72 bit := uint32(1) << uint(s&31) 73 if s >= uint32(32*len(sig.wanted)) { 74 return false 75 } 76 77 sig.delivering.Add(1) 78 // We are running in the signal handler; defer is not available. 79 80 if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 { 81 sig.delivering.Add(-1) 82 return false 83 } 84 85 // Add signal to outgoing queue. 86 for { 87 mask := sig.mask[s/32] 88 if mask&bit != 0 { 89 sig.delivering.Add(-1) 90 return true // signal already in queue 91 } 92 if atomic.Cas(&sig.mask[s/32], mask, mask|bit) { 93 break 94 } 95 } 96 97 // Notify receiver that queue has new bit. 98 Send: 99 for { 100 switch sig.state.Load() { 101 default: 102 throw("sigsend: inconsistent state") 103 case sigIdle: 104 if sig.state.CompareAndSwap(sigIdle, sigSending) { 105 break Send 106 } 107 case sigSending: 108 // notification already pending 109 break Send 110 case sigReceiving: 111 if sig.state.CompareAndSwap(sigReceiving, sigIdle) { 112 if GOOS == "darwin" || GOOS == "ios" { 113 sigNoteWakeup(&sig.note) 114 break Send 115 } 116 notewakeup(&sig.note) 117 break Send 118 } 119 } 120 } 121 122 sig.delivering.Add(-1) 123 return true 124 } 125 126 // Called to receive the next queued signal. 127 // Must only be called from a single goroutine at a time. 128 // 129 //go:linkname signal_recv os/signal.signal_recv 130 func signal_recv() uint32 { 131 for { 132 // Serve any signals from local copy. 133 for i := uint32(0); i < _NSIG; i++ { 134 if sig.recv[i/32]&(1<<(i&31)) != 0 { 135 sig.recv[i/32] &^= 1 << (i & 31) 136 return i 137 } 138 } 139 140 // Wait for updates to be available from signal sender. 141 Receive: 142 for { 143 switch sig.state.Load() { 144 default: 145 throw("signal_recv: inconsistent state") 146 case sigIdle: 147 if sig.state.CompareAndSwap(sigIdle, sigReceiving) { 148 if GOOS == "darwin" || GOOS == "ios" { 149 sigNoteSleep(&sig.note) 150 break Receive 151 } 152 notetsleepg(&sig.note, -1) 153 noteclear(&sig.note) 154 break Receive 155 } 156 case sigSending: 157 if sig.state.CompareAndSwap(sigSending, sigIdle) { 158 break Receive 159 } 160 } 161 } 162 163 // Incorporate updates from sender into local copy. 164 for i := range sig.mask { 165 sig.recv[i] = atomic.Xchg(&sig.mask[i], 0) 166 } 167 } 168 } 169 170 // signalWaitUntilIdle waits until the signal delivery mechanism is idle. 171 // This is used to ensure that we do not drop a signal notification due 172 // to a race between disabling a signal and receiving a signal. 173 // This assumes that signal delivery has already been disabled for 174 // the signal(s) in question, and here we are just waiting to make sure 175 // that all the signals have been delivered to the user channels 176 // by the os/signal package. 177 // 178 //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle 179 func signalWaitUntilIdle() { 180 // Although the signals we care about have been removed from 181 // sig.wanted, it is possible that another thread has received 182 // a signal, has read from sig.wanted, is now updating sig.mask, 183 // and has not yet woken up the processor thread. We need to wait 184 // until all current signal deliveries have completed. 185 for sig.delivering.Load() != 0 { 186 Gosched() 187 } 188 189 // Although WaitUntilIdle seems like the right name for this 190 // function, the state we are looking for is sigReceiving, not 191 // sigIdle. The sigIdle state is really more like sigProcessing. 192 for sig.state.Load() != sigReceiving { 193 Gosched() 194 } 195 } 196 197 // Must only be called from a single goroutine at a time. 198 // 199 //go:linkname signal_enable os/signal.signal_enable 200 func signal_enable(s uint32) { 201 if !sig.inuse { 202 // This is the first call to signal_enable. Initialize. 203 sig.inuse = true // enable reception of signals; cannot disable 204 if GOOS == "darwin" || GOOS == "ios" { 205 sigNoteSetup(&sig.note) 206 } else { 207 noteclear(&sig.note) 208 } 209 } 210 211 if s >= uint32(len(sig.wanted)*32) { 212 return 213 } 214 215 w := sig.wanted[s/32] 216 w |= 1 << (s & 31) 217 atomic.Store(&sig.wanted[s/32], w) 218 219 i := sig.ignored[s/32] 220 i &^= 1 << (s & 31) 221 atomic.Store(&sig.ignored[s/32], i) 222 223 sigenable(s) 224 } 225 226 // Must only be called from a single goroutine at a time. 227 // 228 //go:linkname signal_disable os/signal.signal_disable 229 func signal_disable(s uint32) { 230 if s >= uint32(len(sig.wanted)*32) { 231 return 232 } 233 sigdisable(s) 234 235 w := sig.wanted[s/32] 236 w &^= 1 << (s & 31) 237 atomic.Store(&sig.wanted[s/32], w) 238 } 239 240 // Must only be called from a single goroutine at a time. 241 // 242 //go:linkname signal_ignore os/signal.signal_ignore 243 func signal_ignore(s uint32) { 244 if s >= uint32(len(sig.wanted)*32) { 245 return 246 } 247 sigignore(s) 248 249 w := sig.wanted[s/32] 250 w &^= 1 << (s & 31) 251 atomic.Store(&sig.wanted[s/32], w) 252 253 i := sig.ignored[s/32] 254 i |= 1 << (s & 31) 255 atomic.Store(&sig.ignored[s/32], i) 256 } 257 258 // sigInitIgnored marks the signal as already ignored. This is called at 259 // program start by initsig. In a shared library initsig is called by 260 // libpreinit, so the runtime may not be initialized yet. 261 // 262 //go:nosplit 263 func sigInitIgnored(s uint32) { 264 i := sig.ignored[s/32] 265 i |= 1 << (s & 31) 266 atomic.Store(&sig.ignored[s/32], i) 267 } 268 269 // Checked by signal handlers. 270 // 271 //go:linkname signal_ignored os/signal.signal_ignored 272 func signal_ignored(s uint32) bool { 273 i := atomic.Load(&sig.ignored[s/32]) 274 return i&(1<<(s&31)) != 0 275 } 276