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