github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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 // BUG(rsc): This package is not yet implemented on Plan 9. 9 10 import ( 11 "os" 12 "sync" 13 ) 14 15 var handlers struct { 16 sync.Mutex 17 m map[chan<- os.Signal]*handler 18 ref [numSig]int64 19 } 20 21 type handler struct { 22 mask [(numSig + 31) / 32]uint32 23 } 24 25 func (h *handler) want(sig int) bool { 26 return (h.mask[sig/32]>>uint(sig&31))&1 != 0 27 } 28 29 func (h *handler) set(sig int) { 30 h.mask[sig/32] |= 1 << uint(sig&31) 31 } 32 33 // Notify causes package signal to relay incoming signals to c. 34 // If no signals are listed, all incoming signals will be relayed to c. 35 // Otherwise, just the listed signals will. 36 // 37 // Package signal will not block sending to c: the caller must ensure 38 // that c has sufficient buffer space to keep up with the expected 39 // signal rate. For a channel used for notification of just one signal value, 40 // a buffer of size 1 is sufficient. 41 // 42 // It is allowed to call Notify multiple times with the same channel: 43 // each call expands the set of signals sent to that channel. 44 // The only way to remove signals from the set is to call Stop. 45 // 46 // It is allowed to call Notify multiple times with different channels 47 // and the same signals: each channel receives copies of incoming 48 // signals independently. 49 func Notify(c chan<- os.Signal, sig ...os.Signal) { 50 if c == nil { 51 panic("os/signal: Notify using nil channel") 52 } 53 54 handlers.Lock() 55 defer handlers.Unlock() 56 57 h := handlers.m[c] 58 if h == nil { 59 if handlers.m == nil { 60 handlers.m = make(map[chan<- os.Signal]*handler) 61 } 62 h = new(handler) 63 handlers.m[c] = h 64 } 65 66 add := func(n int) { 67 if n < 0 { 68 return 69 } 70 if !h.want(n) { 71 h.set(n) 72 if handlers.ref[n] == 0 { 73 enableSignal(n) 74 } 75 handlers.ref[n]++ 76 } 77 } 78 79 if len(sig) == 0 { 80 for n := 0; n < numSig; n++ { 81 add(n) 82 } 83 } else { 84 for _, s := range sig { 85 add(signum(s)) 86 } 87 } 88 } 89 90 // Stop causes package signal to stop relaying incoming signals to c. 91 // It undoes the effect of all prior calls to Notify using c. 92 // When Stop returns, it is guaranteed that c will receive no more signals. 93 func Stop(c chan<- os.Signal) { 94 handlers.Lock() 95 defer handlers.Unlock() 96 97 h := handlers.m[c] 98 if h == nil { 99 return 100 } 101 delete(handlers.m, c) 102 103 for n := 0; n < numSig; n++ { 104 if h.want(n) { 105 handlers.ref[n]-- 106 if handlers.ref[n] == 0 { 107 disableSignal(n) 108 } 109 } 110 } 111 } 112 113 func process(sig os.Signal) { 114 n := signum(sig) 115 if n < 0 { 116 return 117 } 118 119 handlers.Lock() 120 defer handlers.Unlock() 121 122 for c, h := range handlers.m { 123 if h.want(n) { 124 // send but do not block for it 125 select { 126 case c <- sig: 127 default: 128 } 129 } 130 } 131 }