interrupt: fix send on closed
If we get a signal while shutting down, we could end up sending on a closed channel. License: MIT Signed-off-by: Steven Allen <steven@stebalien.com>
Steven Allen committed
Mar 28, 2019 at 02:44 UTC
e4afcb71e893151b54555272c7b3bdc6bbc3eb41
1 file changed
+17
-12
cmd/ipfs/util/signal.go
+17
-12
@@ -15,38 +15,43 @@ import (
15
// IntrHandler helps set up an interrupt handler that can
16
// be cleanly shut down through the io.Closer interface.
17
type IntrHandler struct {
18
- sig chan os.Signal
19
- wg sync.WaitGroup
18
+ closing chan struct{}
19
+ wg sync.WaitGroup
20
}
21
22
func NewIntrHandler() *IntrHandler {
23
- ih := &IntrHandler{}
24
- ih.sig = make(chan os.Signal, 1)
25
- return ih
23
+ return &IntrHandler{closing: make(chan struct{})}
24
}
25
26
func (ih *IntrHandler) Close() error {
29
- close(ih.sig)
27
+ close(ih.closing)
28
ih.wg.Wait()
29
return nil
30
}
31
32
// Handle starts handling the given signals, and will call the handler
35
-// callback function each time a signal is catched. The function is passed
33
+// callback function each time a signal is caught. The function is passed
34
// the number of times the handler has been triggered in total, as
35
// well as the handler itself, so that the handling logic can use the
36
// handler's wait group to ensure clean shutdown when Close() is called.
37
func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ...os.Signal) {
40
- signal.Notify(ih.sig, sigs...)
38
+ notify := make(chan os.Signal, 1)
39
+ signal.Notify(notify, sigs...)
40
ih.wg.Add(1)
41
go func() {
42
defer ih.wg.Done()
43
+ defer signal.Stop(notify)
44
+
45
count := 0
45
- for range ih.sig {
46
- count++
47
- handler(count, ih)
46
+ for {
47
+ select {
48
+ case <-ih.closing:
49
+ return
50
+ case <-notify:
51
+ count++
52
+ handler(count, ih)
53
+ }
54
}
49
- signal.Stop(ih.sig)
55
}()
56
}
57