Correct and improve SIGINT (Ctrl+C) handling.

Since the main SIGINT handler is running as a goroutine, the main
goroutine must be kept active long enough for it to finish or it will be
nuked when the main goroutine exits.  This commit makes that happen by
slightly modifying how it waits for shutdown.

Rather than having the main goroutine only wait for the server to
shutdown, there is now a shutdown channel that is used to signal the main
goroutine to shutdown for all cases such as a graceful shutdown, a
scheduled shutdown, an RPC stop, or a SIGINT.

While here, also add a few prints to indicate a SIGINT was received and
the shutdown progress.
This commit is contained in:
Dave Collins 2013-10-26 16:02:23 -05:00
parent 36bd4b8994
commit 1aa65e6863
2 changed files with 22 additions and 3 deletions

20
btcd.go
View file

@ -13,7 +13,8 @@ import (
)
var (
cfg *config
cfg *config
shutdownChannel = make(chan bool)
)
// btcdMain is the real main function for btcd. It is necessary to work around
@ -71,6 +72,7 @@ func btcdMain() error {
// Ensure the database is sync'd and closed on Ctrl+C.
addInterruptHandler(func() {
log.Infof("Gracefully shutting down the database...")
db.RollbackClose()
})
@ -83,7 +85,21 @@ func btcdMain() error {
}
server.Start()
server.WaitForShutdown()
// Monitor for graceful server shutdown and signal the main goroutine
// when done. This is done in a separate goroutine rather than waiting
// directly so the main goroutine can be signaled for shutdown by either
// a graceful shutdown or from the main interrupt handler. This is
// necessary since the main goroutine must be kept running long enough
// for the interrupt handler goroutine to finish.
go func() {
server.WaitForShutdown()
shutdownChannel <- true
}()
// Wait for shutdown signal from either a graceful server stop or from
// the interrupt handler.
<-shutdownChannel
log.Info("Shutdown complete")
return nil
}

View file

@ -27,10 +27,13 @@ func mainInterruptHandler() {
for {
select {
case <-interruptChannel:
log.Infof("Received SIGINT (Ctrl+C). Shutting down...")
for _, callback := range interruptCallbacks {
callback()
}
os.Exit(0)
// Signal the main goroutine to shutdown.
shutdownChannel <- true
case handler := <-addHandlerChannel:
interruptCallbacks = append(interruptCallbacks, handler)