From c1b327c06abf6876dc4ba57d0e4ea7c5bfad0ebb Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Thu, 3 Oct 2013 09:28:18 -0500 Subject: [PATCH] Make the signal handling concurrent safe. --- signal.go | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/signal.go b/signal.go index e4a42011..6f8340e7 100644 --- a/signal.go +++ b/signal.go @@ -12,9 +12,31 @@ import ( // interruptChannel is used to receive SIGINT (Ctrl+C) signals. var interruptChannel chan os.Signal -// interruptCallbacks is a list of callbacks to invoke when a SIGINT (Ctrl+C) is -// received. -var interruptCallbacks []func() +// addHandlerChannel is used to add an interrupt handler to the list of handlers +// to be invoked on SIGINT (Ctrl+C) signals. +var addHandlerChannel = make(chan func()) + +// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the +// interruptChannel and invokes the registered interruptCallbacks accordingly. +// It also listens for callback registration. It must be run as a goroutine. +func mainInterruptHandler() { + // interruptCallbacks is a list of callbacks to invoke when a + // SIGINT (Ctrl+C) is received. + var interruptCallbacks []func() + + for { + select { + case <-interruptChannel: + for _, callback := range interruptCallbacks { + callback() + } + os.Exit(0) + + case handler := <-addHandlerChannel: + interruptCallbacks = append(interruptCallbacks, handler) + } + } +} // addInterruptHandler adds a handler to call when a SIGINT (Ctrl+C) is // received. @@ -24,13 +46,8 @@ func addInterruptHandler(handler func()) { if interruptChannel == nil { interruptChannel = make(chan os.Signal, 1) signal.Notify(interruptChannel, os.Interrupt) - go func() { - <-interruptChannel - for _, callback := range interruptCallbacks { - callback() - } - os.Exit(0) - }() + go mainInterruptHandler() } - interruptCallbacks = append(interruptCallbacks, handler) + + addHandlerChannel <- handler }