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.
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
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
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.
53 mask
[(_NSIG
+ 31) / 32]uint32
54 wanted
[(_NSIG
+ 31) / 32]uint32
55 ignored
[(_NSIG
+ 31) / 32]uint32
56 recv
[(_NSIG
+ 31) / 32]uint32
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
)) {
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)
85 // Add signal to outgoing queue.
87 mask
:= sig
.mask
[s
/32]
89 atomic
.Xadd(&sig
.delivering
, -1)
90 return true // signal already in queue
92 if atomic
.Cas(&sig
.mask
[s
/32], mask
, mask|bit
) {
97 // Notify receiver that queue has new bit.
100 switch atomic
.Load(&sig
.state
) {
102 throw("sigsend: inconsistent state")
104 if atomic
.Cas(&sig
.state
, sigIdle
, sigSending
) {
108 // notification already pending
111 if atomic
.Cas(&sig
.state
, sigReceiving
, sigIdle
) {
112 if GOOS
== "darwin" || GOOS
== "ios" {
113 sigNoteWakeup(&sig
.note
)
116 notewakeup(&sig
.note
)
122 atomic
.Xadd(&sig
.delivering
, -1)
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 {
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)
139 // Wait for updates to be available from signal sender.
142 switch atomic
.Load(&sig
.state
) {
144 throw("signal_recv: inconsistent state")
146 if atomic
.Cas(&sig
.state
, sigIdle
, sigReceiving
) {
147 if GOOS
== "darwin" || GOOS
== "ios" {
148 sigNoteSleep(&sig
.note
)
151 notetsleepg(&sig
.note
, -1)
156 if atomic
.Cas(&sig
.state
, sigSending
, sigIdle
) {
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 {
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
{
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) {
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
)
208 if s
>= uint32(len(sig
.wanted
)*32) {
212 w
:= sig
.wanted
[s
/32]
214 atomic
.Store(&sig
.wanted
[s
/32], w
)
216 i
:= sig
.ignored
[s
/32]
218 atomic
.Store(&sig
.ignored
[s
/32], i
)
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) {
231 w
:= sig
.wanted
[s
/32]
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) {
244 w
:= sig
.wanted
[s
/32]
246 atomic
.Store(&sig
.wanted
[s
/32], w
)
248 i
:= sig
.ignored
[s
/32]
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.
257 func sigInitIgnored(s
uint32) {
258 i
:= sig
.ignored
[s
/32]
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