PR target/117048 aarch64: Use more canonical and optimization-friendly representation...
[official-gcc.git] / libgo / go / runtime / sigqueue.go
blob49754f57643a66cb6a99c2e333b0ff967f687b04
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.
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.
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.
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.
24 // Transitions between states are done atomically with CAS.
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.
31 //go:build !plan9
33 package runtime
35 import (
36 "runtime/internal/atomic"
37 _ "unsafe" // for go:linkname
40 // sig handles communication between the signal handler and os/signal.
41 // Other than the inuse and recv fields, the fields are accessed atomically.
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.
51 var 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 uint32
58 delivering uint32
59 inuse bool
62 const (
63 sigIdle = iota
64 sigReceiving
65 sigSending
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.
71 func sigsend(s uint32) bool {
72 bit := uint32(1) << uint(s&31)
73 if s >= uint32(32*len(sig.wanted)) {
74 return false
77 atomic.Xadd(&sig.delivering, 1)
78 // We are running in the signal handler; defer is not available.
80 if w := atomic.Load(&sig.wanted[s/32]); w&bit == 0 {
81 atomic.Xadd(&sig.delivering, -1)
82 return false
85 // Add signal to outgoing queue.
86 for {
87 mask := sig.mask[s/32]
88 if mask&bit != 0 {
89 atomic.Xadd(&sig.delivering, -1)
90 return true // signal already in queue
92 if atomic.Cas(&sig.mask[s/32], mask, mask|bit) {
93 break
97 // Notify receiver that queue has new bit.
98 Send:
99 for {
100 switch atomic.Load(&sig.state) {
101 default:
102 throw("sigsend: inconsistent state")
103 case sigIdle:
104 if atomic.Cas(&sig.state, sigIdle, sigSending) {
105 break Send
107 case sigSending:
108 // notification already pending
109 break Send
110 case sigReceiving:
111 if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
112 if GOOS == "darwin" || GOOS == "ios" {
113 sigNoteWakeup(&sig.note)
114 break Send
116 notewakeup(&sig.note)
117 break Send
122 atomic.Xadd(&sig.delivering, -1)
123 return true
126 // Called to receive the next queued signal.
127 // Must only be called from a single goroutine at a time.
128 //go:linkname signal_recv os_1signal.signal__recv
129 func signal_recv() uint32 {
130 for {
131 // Serve any signals from local copy.
132 for i := uint32(0); i < _NSIG; i++ {
133 if sig.recv[i/32]&(1<<(i&31)) != 0 {
134 sig.recv[i/32] &^= 1 << (i & 31)
135 return i
139 // Wait for updates to be available from signal sender.
140 Receive:
141 for {
142 switch atomic.Load(&sig.state) {
143 default:
144 throw("signal_recv: inconsistent state")
145 case sigIdle:
146 if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
147 if GOOS == "darwin" || GOOS == "ios" {
148 sigNoteSleep(&sig.note)
149 break Receive
151 notetsleepg(&sig.note, -1)
152 noteclear(&sig.note)
153 break Receive
155 case sigSending:
156 if atomic.Cas(&sig.state, sigSending, sigIdle) {
157 break Receive
162 // Incorporate updates from sender into local copy.
163 for i := range sig.mask {
164 sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
169 // signalWaitUntilIdle waits until the signal delivery mechanism is idle.
170 // This is used to ensure that we do not drop a signal notification due
171 // to a race between disabling a signal and receiving a signal.
172 // This assumes that signal delivery has already been disabled for
173 // the signal(s) in question, and here we are just waiting to make sure
174 // that all the signals have been delivered to the user channels
175 // by the os/signal package.
176 //go:linkname signalWaitUntilIdle os_1signal.signalWaitUntilIdle
177 func signalWaitUntilIdle() {
178 // Although the signals we care about have been removed from
179 // sig.wanted, it is possible that another thread has received
180 // a signal, has read from sig.wanted, is now updating sig.mask,
181 // and has not yet woken up the processor thread. We need to wait
182 // until all current signal deliveries have completed.
183 for atomic.Load(&sig.delivering) != 0 {
184 Gosched()
187 // Although WaitUntilIdle seems like the right name for this
188 // function, the state we are looking for is sigReceiving, not
189 // sigIdle. The sigIdle state is really more like sigProcessing.
190 for atomic.Load(&sig.state) != sigReceiving {
191 Gosched()
195 // Must only be called from a single goroutine at a time.
196 //go:linkname signal_enable os_1signal.signal__enable
197 func signal_enable(s uint32) {
198 if !sig.inuse {
199 // This is the first call to signal_enable. Initialize.
200 sig.inuse = true // enable reception of signals; cannot disable
201 if GOOS == "darwin" || GOOS == "ios" {
202 sigNoteSetup(&sig.note)
203 } else {
204 noteclear(&sig.note)
208 if s >= uint32(len(sig.wanted)*32) {
209 return
212 w := sig.wanted[s/32]
213 w |= 1 << (s & 31)
214 atomic.Store(&sig.wanted[s/32], w)
216 i := sig.ignored[s/32]
217 i &^= 1 << (s & 31)
218 atomic.Store(&sig.ignored[s/32], i)
220 sigenable(s)
223 // Must only be called from a single goroutine at a time.
224 //go:linkname signal_disable os_1signal.signal__disable
225 func signal_disable(s uint32) {
226 if s >= uint32(len(sig.wanted)*32) {
227 return
229 sigdisable(s)
231 w := sig.wanted[s/32]
232 w &^= 1 << (s & 31)
233 atomic.Store(&sig.wanted[s/32], w)
236 // Must only be called from a single goroutine at a time.
237 //go:linkname signal_ignore os_1signal.signal__ignore
238 func signal_ignore(s uint32) {
239 if s >= uint32(len(sig.wanted)*32) {
240 return
242 sigignore(s)
244 w := sig.wanted[s/32]
245 w &^= 1 << (s & 31)
246 atomic.Store(&sig.wanted[s/32], w)
248 i := sig.ignored[s/32]
249 i |= 1 << (s & 31)
250 atomic.Store(&sig.ignored[s/32], i)
253 // sigInitIgnored marks the signal as already ignored. This is called at
254 // program start by initsig. In a shared library initsig is called by
255 // libpreinit, so the runtime may not be initialized yet.
256 //go:nosplit
257 func sigInitIgnored(s uint32) {
258 i := sig.ignored[s/32]
259 i |= 1 << (s & 31)
260 atomic.Store(&sig.ignored[s/32], i)
263 // Checked by signal handlers.
264 //go:linkname signal_ignored os_1signal.signal__ignored
265 func signal_ignored(s uint32) bool {
266 i := atomic.Load(&sig.ignored[s/32])
267 return i&(1<<(s&31)) != 0