From e4afcb71e893151b54555272c7b3bdc6bbc3eb41 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 28 Mar 2019 02:44:25 +0000 Subject: [PATCH] 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 --- cmd/ipfs/util/signal.go | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/cmd/ipfs/util/signal.go b/cmd/ipfs/util/signal.go index 1f290c0b7aa..393a953b907 100644 --- a/cmd/ipfs/util/signal.go +++ b/cmd/ipfs/util/signal.go @@ -15,38 +15,43 @@ import ( // IntrHandler helps set up an interrupt handler that can // be cleanly shut down through the io.Closer interface. type IntrHandler struct { - sig chan os.Signal - wg sync.WaitGroup + closing chan struct{} + wg sync.WaitGroup } func NewIntrHandler() *IntrHandler { - ih := &IntrHandler{} - ih.sig = make(chan os.Signal, 1) - return ih + return &IntrHandler{closing: make(chan struct{})} } func (ih *IntrHandler) Close() error { - close(ih.sig) + close(ih.closing) ih.wg.Wait() return nil } // Handle starts handling the given signals, and will call the handler -// callback function each time a signal is catched. The function is passed +// callback function each time a signal is caught. The function is passed // the number of times the handler has been triggered in total, as // well as the handler itself, so that the handling logic can use the // handler's wait group to ensure clean shutdown when Close() is called. func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ...os.Signal) { - signal.Notify(ih.sig, sigs...) + notify := make(chan os.Signal, 1) + signal.Notify(notify, sigs...) ih.wg.Add(1) go func() { defer ih.wg.Done() + defer signal.Stop(notify) + count := 0 - for range ih.sig { - count++ - handler(count, ih) + for { + select { + case <-ih.closing: + return + case <-notify: + count++ + handler(count, ih) + } } - signal.Stop(ih.sig) }() }