github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/os/signal/signal.go (about) 1 // Copyright 2012 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 package signal 6 7 import ( 8 "os" 9 "sync" 10 ) 11 12 var handlers struct { 13 sync.Mutex 14 // Map a channel to the signals that should be sent to it. 15 m map[chan<- os.Signal]*handler 16 // Map a signal to the number of channels receiving it. 17 ref [numSig]int64 18 // Map channels to signals while the channel is being stopped. 19 // Not a map because entries live here only very briefly. 20 // We need a separate container because we need m to correspond to ref 21 // at all times, and we also need to keep track of the *handler 22 // value for a channel being stopped. See the Stop function. 23 stopping []stopping 24 } 25 26 type stopping struct { 27 c chan<- os.Signal 28 h *handler 29 } 30 31 type handler struct { 32 mask [(numSig + 31) / 32]uint32 33 } 34 35 func (h *handler) want(sig int) bool { 36 return (h.mask[sig/32]>>uint(sig&31))&1 != 0 37 } 38 39 func (h *handler) set(sig int) { 40 h.mask[sig/32] |= 1 << uint(sig&31) 41 } 42 43 func (h *handler) clear(sig int) { 44 h.mask[sig/32] &^= 1 << uint(sig&31) 45 } 46 47 // Stop relaying the signals, sigs, to any channels previously registered to 48 // receive them and either reset the signal handlers to their original values 49 // (action=disableSignal) or ignore the signals (action=ignoreSignal). 50 func cancel(sigs []os.Signal, action func(int)) { 51 handlers.Lock() 52 defer handlers.Unlock() 53 54 remove := func(n int) { 55 var zerohandler handler 56 57 for c, h := range handlers.m { 58 if h.want(n) { 59 handlers.ref[n]-- 60 h.clear(n) 61 if h.mask == zerohandler.mask { 62 delete(handlers.m, c) 63 } 64 } 65 } 66 67 action(n) 68 } 69 70 if len(sigs) == 0 { 71 for n := 0; n < numSig; n++ { 72 remove(n) 73 } 74 } else { 75 for _, s := range sigs { 76 remove(signum(s)) 77 } 78 } 79 } 80 81 // Ignore causes the provided signals to be ignored. If they are received by 82 // the program, nothing will happen. Ignore undoes the effect of any prior 83 // calls to Notify for the provided signals. 84 // If no signals are provided, all incoming signals will be ignored. 85 func Ignore(sig ...os.Signal) { 86 cancel(sig, ignoreSignal) 87 } 88 89 // Notify causes package signal to relay incoming signals to c. 90 // If no signals are provided, all incoming signals will be relayed to c. 91 // Otherwise, just the provided signals will. 92 // 93 // Package signal will not block sending to c: the caller must ensure 94 // that c has sufficient buffer space to keep up with the expected 95 // signal rate. For a channel used for notification of just one signal value, 96 // a buffer of size 1 is sufficient. 97 // 98 // It is allowed to call Notify multiple times with the same channel: 99 // each call expands the set of signals sent to that channel. 100 // The only way to remove signals from the set is to call Stop. 101 // 102 // It is allowed to call Notify multiple times with different channels 103 // and the same signals: each channel receives copies of incoming 104 // signals independently. 105 func Notify(c chan<- os.Signal, sig ...os.Signal) { 106 if c == nil { 107 panic("os/signal: Notify using nil channel") 108 } 109 110 handlers.Lock() 111 defer handlers.Unlock() 112 113 h := handlers.m[c] 114 if h == nil { 115 if handlers.m == nil { 116 handlers.m = make(map[chan<- os.Signal]*handler) 117 } 118 h = new(handler) 119 handlers.m[c] = h 120 } 121 122 add := func(n int) { 123 if n < 0 { 124 return 125 } 126 if !h.want(n) { 127 h.set(n) 128 if handlers.ref[n] == 0 { 129 enableSignal(n) 130 } 131 handlers.ref[n]++ 132 } 133 } 134 135 if len(sig) == 0 { 136 for n := 0; n < numSig; n++ { 137 add(n) 138 } 139 } else { 140 for _, s := range sig { 141 add(signum(s)) 142 } 143 } 144 } 145 146 // Reset undoes the effect of any prior calls to Notify for the provided 147 // signals. 148 // If no signals are provided, all signal handlers will be reset. 149 func Reset(sig ...os.Signal) { 150 cancel(sig, disableSignal) 151 } 152 153 // Stop causes package signal to stop relaying incoming signals to c. 154 // It undoes the effect of all prior calls to Notify using c. 155 // When Stop returns, it is guaranteed that c will receive no more signals. 156 func Stop(c chan<- os.Signal) { 157 handlers.Lock() 158 159 h := handlers.m[c] 160 if h == nil { 161 handlers.Unlock() 162 return 163 } 164 delete(handlers.m, c) 165 166 for n := 0; n < numSig; n++ { 167 if h.want(n) { 168 handlers.ref[n]-- 169 if handlers.ref[n] == 0 { 170 disableSignal(n) 171 } 172 } 173 } 174 175 // Signals will no longer be delivered to the channel. 176 // We want to avoid a race for a signal such as SIGINT: 177 // it should be either delivered to the channel, 178 // or the program should take the default action (that is, exit). 179 // To avoid the possibility that the signal is delivered, 180 // and the signal handler invoked, and then Stop deregisters 181 // the channel before the process function below has a chance 182 // to send it on the channel, put the channel on a list of 183 // channels being stopped and wait for signal delivery to 184 // quiesce before fully removing it. 185 186 handlers.stopping = append(handlers.stopping, stopping{c, h}) 187 188 handlers.Unlock() 189 190 signalWaitUntilIdle() 191 192 handlers.Lock() 193 194 for i, s := range handlers.stopping { 195 if s.c == c { 196 handlers.stopping = append(handlers.stopping[:i], handlers.stopping[i+1:]...) 197 break 198 } 199 } 200 201 handlers.Unlock() 202 } 203 204 // Wait until there are no more signals waiting to be delivered. 205 // Defined by the runtime package. 206 func signalWaitUntilIdle() 207 208 func process(sig os.Signal) { 209 n := signum(sig) 210 if n < 0 { 211 return 212 } 213 214 handlers.Lock() 215 defer handlers.Unlock() 216 217 for c, h := range handlers.m { 218 if h.want(n) { 219 // send but do not block for it 220 select { 221 case c <- sig: 222 default: 223 } 224 } 225 } 226 227 // Avoid the race mentioned in Stop. 228 for _, d := range handlers.stopping { 229 if d.h.want(n) { 230 select { 231 case d.c <- sig: 232 default: 233 } 234 } 235 } 236 }