github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 m map[chan<- os.Signal]*handler 15 ref [numSig]int64 16 } 17 18 type handler struct { 19 mask [(numSig + 31) / 32]uint32 20 } 21 22 func (h *handler) want(sig int) bool { 23 return (h.mask[sig/32]>>uint(sig&31))&1 != 0 24 } 25 26 func (h *handler) set(sig int) { 27 h.mask[sig/32] |= 1 << uint(sig&31) 28 } 29 30 func (h *handler) clear(sig int) { 31 h.mask[sig/32] &^= 1 << uint(sig&31) 32 } 33 34 // Stop relaying the signals, sigs, to any channels previously registered to 35 // receive them and either reset the signal handlers to their original values 36 // (action=disableSignal) or ignore the signals (action=ignoreSignal). 37 func cancel(sigs []os.Signal, action func(int)) { 38 handlers.Lock() 39 defer handlers.Unlock() 40 41 remove := func(n int) { 42 var zerohandler handler 43 44 for c, h := range handlers.m { 45 if h.want(n) { 46 handlers.ref[n]-- 47 h.clear(n) 48 if h.mask == zerohandler.mask { 49 delete(handlers.m, c) 50 } 51 } 52 } 53 54 action(n) 55 } 56 57 if len(sigs) == 0 { 58 for n := 0; n < numSig; n++ { 59 remove(n) 60 } 61 } else { 62 for _, s := range sigs { 63 remove(signum(s)) 64 } 65 } 66 } 67 68 // Ignore causes the provided signals to be ignored. If they are received by 69 // the program, nothing will happen. Ignore undoes the effect of any prior 70 // calls to Notify for the provided signals. 71 // If no signals are provided, all incoming signals will be ignored. 72 func Ignore(sig ...os.Signal) { 73 cancel(sig, ignoreSignal) 74 } 75 76 // Notify causes package signal to relay incoming signals to c. 77 // If no signals are provided, all incoming signals will be relayed to c. 78 // Otherwise, just the provided signals will. 79 // 80 // Package signal will not block sending to c: the caller must ensure 81 // that c has sufficient buffer space to keep up with the expected 82 // signal rate. For a channel used for notification of just one signal value, 83 // a buffer of size 1 is sufficient. 84 // 85 // It is allowed to call Notify multiple times with the same channel: 86 // each call expands the set of signals sent to that channel. 87 // The only way to remove signals from the set is to call Stop. 88 // 89 // It is allowed to call Notify multiple times with different channels 90 // and the same signals: each channel receives copies of incoming 91 // signals independently. 92 func Notify(c chan<- os.Signal, sig ...os.Signal) { 93 if c == nil { 94 panic("os/signal: Notify using nil channel") 95 } 96 97 handlers.Lock() 98 defer handlers.Unlock() 99 100 h := handlers.m[c] 101 if h == nil { 102 if handlers.m == nil { 103 handlers.m = make(map[chan<- os.Signal]*handler) 104 } 105 h = new(handler) 106 handlers.m[c] = h 107 } 108 109 add := func(n int) { 110 if n < 0 { 111 return 112 } 113 if !h.want(n) { 114 h.set(n) 115 if handlers.ref[n] == 0 { 116 enableSignal(n) 117 } 118 handlers.ref[n]++ 119 } 120 } 121 122 if len(sig) == 0 { 123 for n := 0; n < numSig; n++ { 124 add(n) 125 } 126 } else { 127 for _, s := range sig { 128 add(signum(s)) 129 } 130 } 131 } 132 133 // Reset undoes the effect of any prior calls to Notify for the provided 134 // signals. 135 // If no signals are provided, all signal handlers will be reset. 136 func Reset(sig ...os.Signal) { 137 cancel(sig, disableSignal) 138 } 139 140 // Stop causes package signal to stop relaying incoming signals to c. 141 // It undoes the effect of all prior calls to Notify using c. 142 // When Stop returns, it is guaranteed that c will receive no more signals. 143 func Stop(c chan<- os.Signal) { 144 handlers.Lock() 145 defer handlers.Unlock() 146 147 h := handlers.m[c] 148 if h == nil { 149 return 150 } 151 delete(handlers.m, c) 152 153 for n := 0; n < numSig; n++ { 154 if h.want(n) { 155 handlers.ref[n]-- 156 if handlers.ref[n] == 0 { 157 disableSignal(n) 158 } 159 } 160 } 161 } 162 163 func process(sig os.Signal) { 164 n := signum(sig) 165 if n < 0 { 166 return 167 } 168 169 handlers.Lock() 170 defer handlers.Unlock() 171 172 for c, h := range handlers.m { 173 if h.want(n) { 174 // send but do not block for it 175 select { 176 case c <- sig: 177 default: 178 } 179 } 180 } 181 }