github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/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" 34 ) 35 36 var sig struct { 37 note note 38 mask [(_NSIG + 31) / 32]uint32 39 wanted [(_NSIG + 31) / 32]uint32 40 recv [(_NSIG + 31) / 32]uint32 41 state uint32 42 inuse bool 43 } 44 45 const ( 46 sigIdle = iota 47 sigReceiving 48 sigSending 49 ) 50 51 // Called from sighandler to send a signal back out of the signal handling thread. 52 // Reports whether the signal was sent. If not, the caller typically crashes the program. 53 func sigsend(s uint32) bool { 54 bit := uint32(1) << uint(s&31) 55 if !sig.inuse || s >= uint32(32*len(sig.wanted)) || sig.wanted[s/32]&bit == 0 { 56 return false 57 } 58 59 // Add signal to outgoing queue. 60 for { 61 mask := sig.mask[s/32] 62 if mask&bit != 0 { 63 return true // signal already in queue 64 } 65 if atomic.Cas(&sig.mask[s/32], mask, mask|bit) { 66 break 67 } 68 } 69 70 // Notify receiver that queue has new bit. 71 Send: 72 for { 73 switch atomic.Load(&sig.state) { 74 default: 75 throw("sigsend: inconsistent state") 76 case sigIdle: 77 if atomic.Cas(&sig.state, sigIdle, sigSending) { 78 break Send 79 } 80 case sigSending: 81 // notification already pending 82 break Send 83 case sigReceiving: 84 if atomic.Cas(&sig.state, sigReceiving, sigIdle) { 85 notewakeup(&sig.note) 86 break Send 87 } 88 } 89 } 90 91 return true 92 } 93 94 // Called to receive the next queued signal. 95 // Must only be called from a single goroutine at a time. 96 //go:linkname signal_recv os/signal.signal_recv 97 func signal_recv() uint32 { 98 for { 99 // Serve any signals from local copy. 100 for i := uint32(0); i < _NSIG; i++ { 101 if sig.recv[i/32]&(1<<(i&31)) != 0 { 102 sig.recv[i/32] &^= 1 << (i & 31) 103 return i 104 } 105 } 106 107 // Wait for updates to be available from signal sender. 108 Receive: 109 for { 110 switch atomic.Load(&sig.state) { 111 default: 112 throw("signal_recv: inconsistent state") 113 case sigIdle: 114 if atomic.Cas(&sig.state, sigIdle, sigReceiving) { 115 notetsleepg(&sig.note, -1) 116 noteclear(&sig.note) 117 break Receive 118 } 119 case sigSending: 120 if atomic.Cas(&sig.state, sigSending, sigIdle) { 121 break Receive 122 } 123 } 124 } 125 126 // Incorporate updates from sender into local copy. 127 for i := range sig.mask { 128 sig.recv[i] = atomic.Xchg(&sig.mask[i], 0) 129 } 130 } 131 } 132 133 // Must only be called from a single goroutine at a time. 134 //go:linkname signal_enable os/signal.signal_enable 135 func signal_enable(s uint32) { 136 if !sig.inuse { 137 // The first call to signal_enable is for us 138 // to use for initialization. It does not pass 139 // signal information in m. 140 sig.inuse = true // enable reception of signals; cannot disable 141 noteclear(&sig.note) 142 return 143 } 144 145 if s >= uint32(len(sig.wanted)*32) { 146 return 147 } 148 sig.wanted[s/32] |= 1 << (s & 31) 149 sigenable(s) 150 } 151 152 // Must only be called from a single goroutine at a time. 153 //go:linkname signal_disable os/signal.signal_disable 154 func signal_disable(s uint32) { 155 if s >= uint32(len(sig.wanted)*32) { 156 return 157 } 158 sig.wanted[s/32] &^= 1 << (s & 31) 159 sigdisable(s) 160 } 161 162 // Must only be called from a single goroutine at a time. 163 //go:linkname signal_ignore os/signal.signal_ignore 164 func signal_ignore(s uint32) { 165 if s >= uint32(len(sig.wanted)*32) { 166 return 167 } 168 sig.wanted[s/32] &^= 1 << (s & 31) 169 sigignore(s) 170 } 171 172 // This runs on a foreign stack, without an m or a g. No stack split. 173 //go:nosplit 174 //go:norace 175 func badsignal(sig uintptr) { 176 cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) 177 } 178 179 func badsignalgo(sig uintptr) { 180 if !sigsend(uint32(sig)) { 181 // A foreign thread received the signal sig, and the 182 // Go code does not want to handle it. 183 raisebadsignal(int32(sig)) 184 } 185 }