]>
Commit | Line | Data |
---|---|---|
f8d9fa9e ILT |
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 | package runtime | |
28 | ||
29 | import "unsafe" | |
30 | ||
31 | var sig struct { | |
32 | note note | |
33 | mask [(_NSIG + 31) / 32]uint32 | |
34 | wanted [(_NSIG + 31) / 32]uint32 | |
35 | recv [(_NSIG + 31) / 32]uint32 | |
36 | state uint32 | |
37 | inuse bool | |
38 | } | |
39 | ||
40 | const ( | |
41 | sigIdle = iota | |
42 | sigReceiving | |
43 | sigSending | |
44 | ) | |
45 | ||
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 { | |
51 | return false | |
52 | } | |
53 | ||
54 | // Add signal to outgoing queue. | |
55 | for { | |
56 | mask := sig.mask[s/32] | |
57 | if mask&bit != 0 { | |
58 | return true // signal already in queue | |
59 | } | |
60 | if cas(&sig.mask[s/32], mask, mask|bit) { | |
61 | break | |
62 | } | |
63 | } | |
64 | ||
65 | // Notify receiver that queue has new bit. | |
66 | Send: | |
67 | for { | |
68 | switch atomicload(&sig.state) { | |
69 | default: | |
70 | gothrow("sigsend: inconsistent state") | |
71 | case sigIdle: | |
72 | if cas(&sig.state, sigIdle, sigSending) { | |
73 | break Send | |
74 | } | |
75 | case sigSending: | |
76 | // notification already pending | |
77 | break Send | |
78 | case sigReceiving: | |
79 | if cas(&sig.state, sigReceiving, sigIdle) { | |
80 | notewakeup(&sig.note) | |
81 | break Send | |
82 | } | |
83 | } | |
84 | } | |
85 | ||
86 | return true | |
87 | } | |
88 | ||
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 { | |
92 | for { | |
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) | |
97 | return i | |
98 | } | |
99 | } | |
100 | ||
101 | // Wait for updates to be available from signal sender. | |
102 | Receive: | |
103 | for { | |
104 | switch atomicload(&sig.state) { | |
105 | default: | |
106 | gothrow("signal_recv: inconsistent state") | |
107 | case sigIdle: | |
108 | if cas(&sig.state, sigIdle, sigReceiving) { | |
109 | notetsleepg(&sig.note, -1) | |
110 | noteclear(&sig.note) | |
111 | break Receive | |
112 | } | |
113 | case sigSending: | |
114 | if cas(&sig.state, sigSending, sigIdle) { | |
115 | break Receive | |
116 | } | |
117 | } | |
118 | } | |
119 | ||
120 | // Incorporate updates from sender into local copy. | |
121 | for i := range sig.mask { | |
122 | sig.recv[i] = xchg(&sig.mask[i], 0) | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | // Must only be called from a single goroutine at a time. | |
128 | func signal_enable(s uint32) { | |
129 | if !sig.inuse { | |
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 | |
134 | noteclear(&sig.note) | |
135 | return | |
136 | } | |
137 | ||
138 | if int(s) >= len(sig.wanted)*32 { | |
139 | return | |
140 | } | |
141 | sig.wanted[s/32] |= 1 << (s & 31) | |
142 | sigenable_go(s) | |
143 | } | |
144 | ||
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 { | |
148 | return | |
149 | } | |
150 | sig.wanted[s/32] &^= 1 << (s & 31) | |
151 | sigdisable_go(s) | |
152 | } | |
153 | ||
154 | // This runs on a foreign stack, without an m or a g. No stack split. | |
155 | //go:nosplit | |
156 | func badsignal(sig uintptr) { | |
c271e224 ILT |
157 | // Some external libraries, for example, OpenBLAS, create worker threads in |
158 | // a global constructor. If we're doing cpu profiling, and the SIGPROF signal | |
159 | // comes to one of the foreign threads before we make our first cgo call, the | |
160 | // call to cgocallback below will bring down the whole process. | |
161 | // It's better to miss a few SIGPROF signals than to abort in this case. | |
162 | // See http://golang.org/issue/9456. | |
163 | if _SIGPROF != 0 && sig == _SIGPROF && needextram != 0 { | |
164 | return | |
165 | } | |
f8d9fa9e ILT |
166 | cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) |
167 | } | |
168 | ||
169 | func sigenable_m() | |
170 | func sigdisable_m() | |
171 | ||
172 | func sigenable_go(s uint32) { | |
173 | g := getg() | |
174 | g.m.scalararg[0] = uintptr(s) | |
175 | onM(sigenable_m) | |
176 | } | |
177 | ||
178 | func sigdisable_go(s uint32) { | |
179 | g := getg() | |
180 | g.m.scalararg[0] = uintptr(s) | |
181 | onM(sigdisable_m) | |
182 | } |