Make the signal handling concurrent safe.

This commit is contained in:
Dave Collins 2013-10-03 09:28:18 -05:00
parent 35c95f0a36
commit c1b327c06a

View file

@ -12,9 +12,31 @@ import (
// interruptChannel is used to receive SIGINT (Ctrl+C) signals. // interruptChannel is used to receive SIGINT (Ctrl+C) signals.
var interruptChannel chan os.Signal var interruptChannel chan os.Signal
// interruptCallbacks is a list of callbacks to invoke when a SIGINT (Ctrl+C) is // addHandlerChannel is used to add an interrupt handler to the list of handlers
// received. // to be invoked on SIGINT (Ctrl+C) signals.
var interruptCallbacks []func() 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 // addInterruptHandler adds a handler to call when a SIGINT (Ctrl+C) is
// received. // received.
@ -24,13 +46,8 @@ func addInterruptHandler(handler func()) {
if interruptChannel == nil { if interruptChannel == nil {
interruptChannel = make(chan os.Signal, 1) interruptChannel = make(chan os.Signal, 1)
signal.Notify(interruptChannel, os.Interrupt) signal.Notify(interruptChannel, os.Interrupt)
go func() { go mainInterruptHandler()
<-interruptChannel
for _, callback := range interruptCallbacks {
callback()
}
os.Exit(0)
}()
} }
interruptCallbacks = append(interruptCallbacks, handler)
addHandlerChannel <- handler
} }