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.
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
33 mask
[(_NSIG
+ 31) / 32]uint32
34 wanted
[(_NSIG
+ 31) / 32]uint32
35 recv
[(_NSIG
+ 31) / 32]uint32
46 // Called from sighandler to send a signal back out of the signal handling thread.
47 // Reports whether the signal was sent. If not, the caller typically crashes the program.
48 func sigsend(s
int32) bool {
49 bit
:= uint32(1) << uint(s
&31)
50 if !sig
.inuse || s
< 0 ||
int(s
) >= 32*len(sig
.wanted
) || sig
.wanted
[s
/32]&bit
== 0 {
54 // Add signal to outgoing queue.
56 mask
:= sig
.mask
[s
/32]
58 return true // signal already in queue
60 if cas(&sig
.mask
[s
/32], mask
, mask|bit
) {
65 // Notify receiver that queue has new bit.
68 switch atomicload(&sig
.state
) {
70 gothrow("sigsend: inconsistent state")
72 if cas(&sig
.state
, sigIdle
, sigSending
) {
76 // notification already pending
79 if cas(&sig
.state
, sigReceiving
, sigIdle
) {
89 // Called to receive the next queued signal.
90 // Must only be called from a single goroutine at a time.
91 func signal_recv() uint32 {
93 // Serve any signals from local copy.
94 for i
:= uint32(0); i
< _NSIG
; i
++ {
95 if sig
.recv
[i
/32]&(1<<(i
&31)) != 0 {
96 sig
.recv
[i
/32] &^= 1 << (i
& 31)
101 // Wait for updates to be available from signal sender.
104 switch atomicload(&sig
.state
) {
106 gothrow("signal_recv: inconsistent state")
108 if cas(&sig
.state
, sigIdle
, sigReceiving
) {
109 notetsleepg(&sig
.note
, -1)
114 if cas(&sig
.state
, sigSending
, sigIdle
) {
120 // Incorporate updates from sender into local copy.
121 for i
:= range sig
.mask
{
122 sig
.recv
[i
] = xchg(&sig
.mask
[i
], 0)
127 // Must only be called from a single goroutine at a time.
128 func signal_enable(s
uint32) {
130 // The first call to signal_enable is for us
131 // to use for initialization. It does not pass
132 // signal information in m.
133 sig
.inuse
= true // enable reception of signals; cannot disable
138 if int(s
) >= len(sig
.wanted
)*32 {
141 sig
.wanted
[s
/32] |
= 1 << (s
& 31)
145 // Must only be called from a single goroutine at a time.
146 func signal_disable(s
uint32) {
147 if int(s
) >= len(sig
.wanted
)*32 {
150 sig
.wanted
[s
/32] &^= 1 << (s
& 31)
154 // This runs on a foreign stack, without an m or a g. No stack split.
156 func badsignal(sig
uintptr) {
157 cgocallback(unsafe
.Pointer(funcPC(sigsend
)), noescape(unsafe
.Pointer(&sig
)), unsafe
.Sizeof(sig
))
163 func sigenable_go(s
uint32) {
165 g
.m
.scalararg
[0] = uintptr(s
)
169 func sigdisable_go(s
uint32) {
171 g
.m
.scalararg
[0] = uintptr(s
)