diff --git a/dcrd.go b/dcrd.go index 705b5cbca3..914eb5213e 100644 --- a/dcrd.go +++ b/dcrd.go @@ -41,12 +41,14 @@ func dcrdMain(serverChan chan<- *server) error { cfg = tcfg defer backendLog.Flush() - interrupted := interruptListener() + // Get a channel that will be closed when a shutdown signal has been + // triggered either from an OS signal such as SIGINT (Ctrl+C) or from + // another subsystem such as the RPC server. + interruptedChan := interruptListener() defer dcrdLog.Info("Shutdown complete") - // Show version at startup. + // Show version and home dir at startup. dcrdLog.Infof("Version %s", version()) - // Show dcrd home dir location dcrdLog.Infof("Home dir: %s", cfg.HomeDir) // Enable http profiling server if requested. @@ -106,11 +108,8 @@ func dcrdMain(serverChan chan<- *server) error { go drainOutgoingPipeMessages() } - if interruptRequested(interrupted) { - return nil - } - - if interruptRequested(interrupted) { + // Return now if an interrupt signal was triggered. + if interruptRequested(interruptedChan) { return nil } @@ -122,12 +121,14 @@ func dcrdMain(serverChan chan<- *server) error { return err } defer func() { + // Ensure the database is sync'd and closed on shutdown. lifetimeNotifier.notifyShutdownEvent(lifetimeEventDBOpen) dcrdLog.Infof("Gracefully shutting down the database...") db.Close() }() - if interruptRequested(interrupted) { + // Return now if an interrupt signal was triggered. + if interruptRequested(interruptedChan) { return nil } @@ -182,15 +183,16 @@ func dcrdMain(serverChan chan<- *server) error { serverChan <- server } - if interruptRequested(interrupted) { + if interruptRequested(interruptedChan) { return nil } lifetimeNotifier.notifyStartupComplete() // Wait until the interrupt signal is received from an OS signal or - // shutdown is requested through the RPC server. - <-interrupted + // shutdown is requested through one of the subsystems such as the RPC + // server. + <-interruptedChan return nil } diff --git a/service_windows.go b/service_windows.go index 30bb8b2f4f..8dbfdc0f35 100644 --- a/service_windows.go +++ b/service_windows.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2013-2016 The btcsuite developers // Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -86,12 +86,8 @@ loop: // more commands while pending. changes <- svc.Status{State: svc.StopPending} - // Signal the main function to exit if shutdown - // was not already requested. - select { - case shutdownRequestChannel <- struct{}{}: - default: - } + // Signal the main function to exit. + shutdownRequestChannel <- struct{}{} default: elog.Error(1, fmt.Sprintf("Unexpected control "+ diff --git a/signal.go b/signal.go index 04d1988392..868c8d0c23 100644 --- a/signal.go +++ b/signal.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2013-2016 The btcsuite developers // Copyright (c) 2015-2016 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -18,24 +18,41 @@ var shutdownRequestChannel = make(chan struct{}) // shutdown. This may be modified during init depending on the platform. var interruptSignals = []os.Signal{os.Interrupt} -// interruptListener listens for SIGINT (Ctrl+C) signals and shutdown requests -// from shutdownRequestChannel. It returns a channel that is closed when either -// signal is received. +// interruptListener listens for OS Signals such as SIGINT (Ctrl+C) and shutdown +// requests from shutdownRequestChannel. It returns a channel that is closed +// when either signal is received. func interruptListener() <-chan struct{} { c := make(chan struct{}) - go func() { interruptChannel := make(chan os.Signal, 1) signal.Notify(interruptChannel, interruptSignals...) + // Listen for initial shutdown signal and close the returned + // channel to notify the caller. select { case sig := <-interruptChannel: - dcrdLog.Infof("Received signal (%s). Shutting down...", sig) + dcrdLog.Infof("Received signal (%s). Shutting down...", + sig) + case <-shutdownRequestChannel: dcrdLog.Infof("Shutdown requested. Shutting down...") } - close(c) + + // Listen for repeated signals and display a message so the user + // knows the shutdown is in progress and the process is not + // hung. + for { + select { + case sig := <-interruptChannel: + dcrdLog.Infof("Received signal (%s). Already "+ + "shutting down...", sig) + + case <-shutdownRequestChannel: + dcrdLog.Info("Shutdown requested. Already " + + "shutting down...") + } + } }() return c @@ -49,6 +66,7 @@ func interruptRequested(interrupted <-chan struct{}) bool { case <-interrupted: return true default: - return false } + + return false }