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