github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/runtime/sigqueue.go (about) 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 29 package runtime 30 31 import ( 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. 47 var 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 inuse bool 55 } 56 57 const ( 58 sigIdle = iota 59 sigReceiving 60 sigSending 61 ) 62 63 // Called from sighandler to send a signal back out of the signal handling thread. 64 // Reports whether the signal was sent. If not, the caller typically crashes the program. 65 func sigsend(s uint32) bool { 66 bit := uint32(1) << uint(s&31) 67 if !sig.inuse || s >= uint32(32*len(sig.wanted)) { 68 return false 69 } 70 71 if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 { 72 return false 73 } 74 75 // Add signal to outgoing queue. 76 for { 77 mask := sig.mask[s/32] 78 if mask&bit != 0 { 79 return true // signal already in queue 80 } 81 if atomic.Cas(&sig.mask[s/32], mask, mask|bit) { 82 break 83 } 84 } 85 86 // Notify receiver that queue has new bit. 87 Send: 88 for { 89 switch atomic.Load(&sig.state) { 90 default: 91 throw("sigsend: inconsistent state") 92 case sigIdle: 93 if atomic.Cas(&sig.state, sigIdle, sigSending) { 94 break Send 95 } 96 case sigSending: 97 // notification already pending 98 break Send 99 case sigReceiving: 100 if atomic.Cas(&sig.state, sigReceiving, sigIdle) { 101 notewakeup(&sig.note) 102 break Send 103 } 104 } 105 } 106 107 return true 108 } 109 110 // Called to receive the next queued signal. 111 // Must only be called from a single goroutine at a time. 112 //go:linkname signal_recv os/signal.signal_recv 113 func signal_recv() uint32 { 114 for { 115 // Serve any signals from local copy. 116 for i := uint32(0); i < _NSIG; i++ { 117 if sig.recv[i/32]&(1<<(i&31)) != 0 { 118 sig.recv[i/32] &^= 1 << (i & 31) 119 return i 120 } 121 } 122 123 // Wait for updates to be available from signal sender. 124 Receive: 125 for { 126 switch atomic.Load(&sig.state) { 127 default: 128 throw("signal_recv: inconsistent state") 129 case sigIdle: 130 if atomic.Cas(&sig.state, sigIdle, sigReceiving) { 131 notetsleepg(&sig.note, -1) 132 noteclear(&sig.note) 133 break Receive 134 } 135 case sigSending: 136 if atomic.Cas(&sig.state, sigSending, sigIdle) { 137 break Receive 138 } 139 } 140 } 141 142 // Incorporate updates from sender into local copy. 143 for i := range sig.mask { 144 sig.recv[i] = atomic.Xchg(&sig.mask[i], 0) 145 } 146 } 147 } 148 149 // signalWaitUntilIdle waits until the signal delivery mechanism is idle. 150 // This is used to ensure that we do not drop a signal notification due 151 // to a race between disabling a signal and receiving a signal. 152 // This assumes that signal delivery has already been disabled for 153 // the signal(s) in question, and here we are just waiting to make sure 154 // that all the signals have been delivered to the user channels 155 // by the os/signal package. 156 //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle 157 func signalWaitUntilIdle() { 158 // Although WaitUntilIdle seems like the right name for this 159 // function, the state we are looking for is sigReceiving, not 160 // sigIdle. The sigIdle state is really more like sigProcessing. 161 for atomic.Load(&sig.state) != sigReceiving { 162 Gosched() 163 } 164 } 165 166 // Must only be called from a single goroutine at a time. 167 //go:linkname signal_enable os/signal.signal_enable 168 func signal_enable(s uint32) { 169 if !sig.inuse { 170 // The first call to signal_enable is for us 171 // to use for initialization. It does not pass 172 // signal information in m. 173 sig.inuse = true // enable reception of signals; cannot disable 174 noteclear(&sig.note) 175 return 176 } 177 178 if s >= uint32(len(sig.wanted)*32) { 179 return 180 } 181 182 w := sig.wanted[s/32] 183 w |= 1 << (s & 31) 184 atomic.Store(&sig.wanted[s/32], w) 185 186 i := sig.ignored[s/32] 187 i &^= 1 << (s & 31) 188 atomic.Store(&sig.ignored[s/32], i) 189 190 sigenable(s) 191 } 192 193 // Must only be called from a single goroutine at a time. 194 //go:linkname signal_disable os/signal.signal_disable 195 func signal_disable(s uint32) { 196 if s >= uint32(len(sig.wanted)*32) { 197 return 198 } 199 sigdisable(s) 200 201 w := sig.wanted[s/32] 202 w &^= 1 << (s & 31) 203 atomic.Store(&sig.wanted[s/32], w) 204 } 205 206 // Must only be called from a single goroutine at a time. 207 //go:linkname signal_ignore os/signal.signal_ignore 208 func signal_ignore(s uint32) { 209 if s >= uint32(len(sig.wanted)*32) { 210 return 211 } 212 sigignore(s) 213 214 w := sig.wanted[s/32] 215 w &^= 1 << (s & 31) 216 atomic.Store(&sig.wanted[s/32], w) 217 218 i := sig.ignored[s/32] 219 i |= 1 << (s & 31) 220 atomic.Store(&sig.ignored[s/32], i) 221 } 222 223 // Checked by signal handlers. 224 func signal_ignored(s uint32) bool { 225 i := atomic.Load(&sig.ignored[s/32]) 226 return i&(1<<(s&31)) != 0 227 }