diff --git a/btcd.go b/btcd.go index 7c3bb3758..b854f2f23 100644 --- a/btcd.go +++ b/btcd.go @@ -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 } diff --git a/signal.go b/signal.go index 6f8340e7b..438f9c7be 100644 --- a/signal.go +++ b/signal.go @@ -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)