044a11c9fc
This rewrites the shutdown logic to simplify the shutdown signalling. All cleanup is now run from deferred functions in the main function and channels are used to signal shutdown either from OS signals or from other subsystems such as the RPC server and windows service controller. The RPC server has been modified to use a new channel for signalling shutdown that is exposed via the RequestedProcessShutdown function instead of directly calling Stop on the server as it previously did. Finally, it adds a few checks for early termination during the main start sequence so the process can be stopped without starting all the subsystems if desired. This is a backport of the equivalent logic from Decred with a few slight modifications. Credits go to @jrick.
71 lines
2 KiB
Go
71 lines
2 KiB
Go
// Copyright (c) 2013-2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
)
|
|
|
|
// shutdownRequestChannel is used to initiate shutdown from one of the
|
|
// subsystems using the same code paths as when an interrupt signal is received.
|
|
var shutdownRequestChannel = make(chan struct{})
|
|
|
|
// interruptSignals defines the default signals to catch in order to do a proper
|
|
// shutdown. This may be modified during init depending on the platform.
|
|
var interruptSignals = []os.Signal{os.Interrupt}
|
|
|
|
// 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:
|
|
btcdLog.Infof("Received signal (%s). Shutting down...",
|
|
sig)
|
|
|
|
case <-shutdownRequestChannel:
|
|
btcdLog.Info("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:
|
|
btcdLog.Infof("Received signal (%s). Already "+
|
|
"shutting down...", sig)
|
|
|
|
case <-shutdownRequestChannel:
|
|
btcdLog.Info("Shutdown requested. Already " +
|
|
"shutting down...")
|
|
}
|
|
}
|
|
}()
|
|
|
|
return c
|
|
}
|
|
|
|
// interruptRequested returns true when the channel returned by
|
|
// interruptListener was closed. This simplifies early shutdown slightly since
|
|
// the caller can just use an if statement instead of a select.
|
|
func interruptRequested(interrupted <-chan struct{}) bool {
|
|
select {
|
|
case <-interrupted:
|
|
return true
|
|
default:
|
|
}
|
|
|
|
return false
|
|
}
|