Source file
src/os/signal/signal.go
1
2
3
4
5 package signal
6
7 import (
8 "context"
9 "os"
10 "sync"
11 )
12
13 var handlers struct {
14 sync.Mutex
15
16 m map[chan<- os.Signal]*handler
17
18 ref [numSig]int64
19
20
21
22
23
24 stopping []stopping
25 }
26
27 type stopping struct {
28 c chan<- os.Signal
29 h *handler
30 }
31
32 type handler struct {
33 mask [(numSig + 31) / 32]uint32
34 }
35
36 func (h *handler) want(sig int) bool {
37 return (h.mask[sig/32]>>uint(sig&31))&1 != 0
38 }
39
40 func (h *handler) set(sig int) {
41 h.mask[sig/32] |= 1 << uint(sig&31)
42 }
43
44 func (h *handler) clear(sig int) {
45 h.mask[sig/32] &^= 1 << uint(sig&31)
46 }
47
48
49
50
51 func cancel(sigs []os.Signal, action func(int)) {
52 handlers.Lock()
53 defer handlers.Unlock()
54
55 remove := func(n int) {
56 var zerohandler handler
57
58 for c, h := range handlers.m {
59 if h.want(n) {
60 handlers.ref[n]--
61 h.clear(n)
62 if h.mask == zerohandler.mask {
63 delete(handlers.m, c)
64 }
65 }
66 }
67
68 action(n)
69 }
70
71 if len(sigs) == 0 {
72 for n := 0; n < numSig; n++ {
73 remove(n)
74 }
75 } else {
76 for _, s := range sigs {
77 remove(signum(s))
78 }
79 }
80 }
81
82
83
84
85
86 func Ignore(sig ...os.Signal) {
87 cancel(sig, ignoreSignal)
88 }
89
90
91 func Ignored(sig os.Signal) bool {
92 sn := signum(sig)
93 return sn >= 0 && signalIgnored(sn)
94 }
95
96 var (
97
98
99
100
101 watchSignalLoopOnce sync.Once
102 watchSignalLoop func()
103 )
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 func Notify(c chan<- os.Signal, sig ...os.Signal) {
122 if c == nil {
123 panic("os/signal: Notify using nil channel")
124 }
125
126 handlers.Lock()
127 defer handlers.Unlock()
128
129 h := handlers.m[c]
130 if h == nil {
131 if handlers.m == nil {
132 handlers.m = make(map[chan<- os.Signal]*handler)
133 }
134 h = new(handler)
135 handlers.m[c] = h
136 }
137
138 add := func(n int) {
139 if n < 0 {
140 return
141 }
142 if !h.want(n) {
143 h.set(n)
144 if handlers.ref[n] == 0 {
145 enableSignal(n)
146
147
148
149 watchSignalLoopOnce.Do(func() {
150 if watchSignalLoop != nil {
151 go watchSignalLoop()
152 }
153 })
154 }
155 handlers.ref[n]++
156 }
157 }
158
159 if len(sig) == 0 {
160 for n := 0; n < numSig; n++ {
161 add(n)
162 }
163 } else {
164 for _, s := range sig {
165 add(signum(s))
166 }
167 }
168 }
169
170
171
172
173 func Reset(sig ...os.Signal) {
174 cancel(sig, disableSignal)
175 }
176
177
178
179
180 func Stop(c chan<- os.Signal) {
181 handlers.Lock()
182
183 h := handlers.m[c]
184 if h == nil {
185 handlers.Unlock()
186 return
187 }
188 delete(handlers.m, c)
189
190 for n := 0; n < numSig; n++ {
191 if h.want(n) {
192 handlers.ref[n]--
193 if handlers.ref[n] == 0 {
194 disableSignal(n)
195 }
196 }
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210 handlers.stopping = append(handlers.stopping, stopping{c, h})
211
212 handlers.Unlock()
213
214 signalWaitUntilIdle()
215
216 handlers.Lock()
217
218 for i, s := range handlers.stopping {
219 if s.c == c {
220 handlers.stopping = append(handlers.stopping[:i], handlers.stopping[i+1:]...)
221 break
222 }
223 }
224
225 handlers.Unlock()
226 }
227
228
229
230 func signalWaitUntilIdle()
231
232 func process(sig os.Signal) {
233 n := signum(sig)
234 if n < 0 {
235 return
236 }
237
238 handlers.Lock()
239 defer handlers.Unlock()
240
241 for c, h := range handlers.m {
242 if h.want(n) {
243
244 select {
245 case c <- sig:
246 default:
247 }
248 }
249 }
250
251
252 for _, d := range handlers.stopping {
253 if d.h.want(n) {
254 select {
255 case d.c <- sig:
256 default:
257 }
258 }
259 }
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277 func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) {
278 ctx, cancel := context.WithCancel(parent)
279 c := &signalCtx{
280 Context: ctx,
281 cancel: cancel,
282 signals: signals,
283 }
284 c.ch = make(chan os.Signal, 1)
285 Notify(c.ch, c.signals...)
286 if ctx.Err() == nil {
287 go func() {
288 select {
289 case <-c.ch:
290 c.cancel()
291 case <-c.Done():
292 }
293 }()
294 }
295 return c, c.stop
296 }
297
298 type signalCtx struct {
299 context.Context
300
301 cancel context.CancelFunc
302 signals []os.Signal
303 ch chan os.Signal
304 }
305
306 func (c *signalCtx) stop() {
307 c.cancel()
308 Stop(c.ch)
309 }
310
311 type stringer interface {
312 String() string
313 }
314
315 func (c *signalCtx) String() string {
316 var buf []byte
317
318
319 name := c.Context.(stringer).String()
320 name = name[:len(name)-len(".WithCancel")]
321 buf = append(buf, "signal.NotifyContext("+name...)
322 if len(c.signals) != 0 {
323 buf = append(buf, ", ["...)
324 for i, s := range c.signals {
325 buf = append(buf, s.String()...)
326 if i != len(c.signals)-1 {
327 buf = append(buf, ' ')
328 }
329 }
330 buf = append(buf, ']')
331 }
332 buf = append(buf, ')')
333 return string(buf)
334 }
335
View as plain text