@cryptotaxi247 / kubo / commits / e4afcb71e

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