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