summaryrefslogtreecommitdiff
path: root/src/pkg/os/signal/signal.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/os/signal/signal.go')
-rw-r--r--src/pkg/os/signal/signal.go77
1 files changed, 56 insertions, 21 deletions
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go
index bce4530e7..dfdcf4061 100644
--- a/src/pkg/os/signal/signal.go
+++ b/src/pkg/os/signal/signal.go
@@ -1,37 +1,72 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// 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.
-// +build darwin freebsd linux netbsd openbsd
-
-// Package signal implements operating system-independent signal handling.
+// Package signal implements access to incoming signals.
package signal
+// BUG(rsc): This package is not yet implemented on Plan 9 and Windows.
+
import (
"os"
- "runtime"
+ "sync"
)
-// Incoming is the global signal channel.
-// All signals received by the program will be delivered to this channel.
-var Incoming <-chan os.Signal
+var handlers struct {
+ sync.Mutex
+ list []handler
+}
+
+type handler struct {
+ c chan<- os.Signal
+ sig os.Signal
+ all bool
+}
+
+// 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.
+//
+func Notify(c chan<- os.Signal, sig ...os.Signal) {
+ if c == nil {
+ panic("os/signal: Notify using nil channel")
+ }
-func process(ch chan<- os.Signal) {
- for {
- var mask uint32 = runtime.Sigrecv()
- for sig := uint(0); sig < 32; sig++ {
- if mask&(1<<sig) != 0 {
- ch <- os.UnixSignal(sig)
+ handlers.Lock()
+ defer handlers.Unlock()
+ if len(sig) == 0 {
+ enableSignal(nil)
+ handlers.list = append(handlers.list, handler{c: c, all: true})
+ } else {
+ for _, s := range sig {
+ // We use nil as a special wildcard value for enableSignal,
+ // so filter it out of the list of arguments. This is safe because
+ // we will never get an incoming nil signal, so discarding the
+ // registration cannot affect the observed behavior.
+ if s != nil {
+ enableSignal(s)
+ handlers.list = append(handlers.list, handler{c: c, sig: s})
}
}
}
}
-func init() {
- runtime.Siginit()
- ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal
- Incoming = ch
- go process(ch)
-}
+func process(sig os.Signal) {
+ handlers.Lock()
+ defer handlers.Unlock()
-// BUG(rsc): This package is unavailable on Plan 9 and Windows.
+ for _, h := range handlers.list {
+ if h.all || h.sig == sig {
+ // send but do not block for it
+ select {
+ case h.c <- sig:
+ default:
+ }
+ }
+ }
+}