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 33package runtime 34 35import ( 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. 51var 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 62const ( 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. 71func 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. 98Send: 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 130func 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 179func 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 200func 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 229func 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 243func 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 263func 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 272func signal_ignored(s uint32) bool { 273 i := atomic.Load(&sig.ignored[s/32]) 274 return i&(1<<(s&31)) != 0 275} 276