diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/os/signal/signal.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/os/signal/signal.go')
-rw-r--r-- | src/os/signal/signal.go | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/os/signal/signal.go b/src/os/signal/signal.go new file mode 100644 index 000000000..300427549 --- /dev/null +++ b/src/os/signal/signal.go @@ -0,0 +1,131 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package signal implements access to incoming signals. +package signal + +// BUG(rsc): This package is not yet implemented on Plan 9. + +import ( + "os" + "sync" +) + +var handlers struct { + sync.Mutex + m map[chan<- os.Signal]*handler + ref [numSig]int64 +} + +type handler struct { + mask [(numSig + 31) / 32]uint32 +} + +func (h *handler) want(sig int) bool { + return (h.mask[sig/32]>>uint(sig&31))&1 != 0 +} + +func (h *handler) set(sig int) { + h.mask[sig/32] |= 1 << uint(sig&31) +} + +// Notify causes package signal to relay incoming signals to c. +// If no signals are listed, all incoming signals will be relayed to c. +// Otherwise, just the listed signals will. +// +// Package signal will not block sending to c: the caller must ensure +// that c has sufficient buffer space to keep up with the expected +// signal rate. For a channel used for notification of just one signal value, +// a buffer of size 1 is sufficient. +// +// It is allowed to call Notify multiple times with the same channel: +// each call expands the set of signals sent to that channel. +// The only way to remove signals from the set is to call Stop. +// +// It is allowed to call Notify multiple times with different channels +// and the same signals: each channel receives copies of incoming +// signals independently. +func Notify(c chan<- os.Signal, sig ...os.Signal) { + if c == nil { + panic("os/signal: Notify using nil channel") + } + + handlers.Lock() + defer handlers.Unlock() + + h := handlers.m[c] + if h == nil { + if handlers.m == nil { + handlers.m = make(map[chan<- os.Signal]*handler) + } + h = new(handler) + handlers.m[c] = h + } + + add := func(n int) { + if n < 0 { + return + } + if !h.want(n) { + h.set(n) + if handlers.ref[n] == 0 { + enableSignal(n) + } + handlers.ref[n]++ + } + } + + if len(sig) == 0 { + for n := 0; n < numSig; n++ { + add(n) + } + } else { + for _, s := range sig { + add(signum(s)) + } + } +} + +// Stop causes package signal to stop relaying incoming signals to c. +// It undoes the effect of all prior calls to Notify using c. +// When Stop returns, it is guaranteed that c will receive no more signals. +func Stop(c chan<- os.Signal) { + handlers.Lock() + defer handlers.Unlock() + + h := handlers.m[c] + if h == nil { + return + } + delete(handlers.m, c) + + for n := 0; n < numSig; n++ { + if h.want(n) { + handlers.ref[n]-- + if handlers.ref[n] == 0 { + disableSignal(n) + } + } + } +} + +func process(sig os.Signal) { + n := signum(sig) + if n < 0 { + return + } + + handlers.Lock() + defer handlers.Unlock() + + for c, h := range handlers.m { + if h.want(n) { + // send but do not block for it + select { + case c <- sig: + default: + } + } + } +} |