main: Convert signal handling to use context.

This converts the signal handling and dcrdMain function to use a context
with cancellation instead of a separate interrupt channel.  It does not
really make much of a difference yet, but the intent is to simplify the
various subsystems in future commits by refactoring them to make use of
the context versus manually handling start and stop in each subsystem.
This commit is contained in:
Dave Collins 2019-03-30 21:02:52 -05:00
parent 074d50f49b
commit 51852570e2
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
2 changed files with 27 additions and 28 deletions

26
dcrd.go
View File

@ -47,10 +47,10 @@ func dcrdMain() error {
}
}()
// Get a channel that will be closed when a shutdown signal has been
// Get a context that will be canceled 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.
interrupt := interruptListener()
ctx := shutdownListener()
defer dcrdLog.Info("Shutdown complete")
// Show version and home dir at startup.
@ -114,8 +114,8 @@ func dcrdMain() error {
go drainOutgoingPipeMessages()
}
// Return now if an interrupt signal was triggered.
if interruptRequested(interrupt) {
// Return now if a shutdown signal was triggered.
if shutdownRequested(ctx) {
return nil
}
@ -133,8 +133,8 @@ func dcrdMain() error {
db.Close()
}()
// Return now if an interrupt signal was triggered.
if interruptRequested(interrupt) {
// Return now if a shutdown signal was triggered.
if shutdownRequested(ctx) {
return nil
}
@ -143,7 +143,7 @@ func dcrdMain() error {
// NOTE: The order is important here because dropping the tx index also
// drops the address index since it relies on it.
if cfg.DropAddrIndex {
if err := indexers.DropAddrIndex(db, interrupt); err != nil {
if err := indexers.DropAddrIndex(db, ctx.Done()); err != nil {
dcrdLog.Errorf("%v", err)
return err
}
@ -151,7 +151,7 @@ func dcrdMain() error {
return nil
}
if cfg.DropTxIndex {
if err := indexers.DropTxIndex(db, interrupt); err != nil {
if err := indexers.DropTxIndex(db, ctx.Done()); err != nil {
dcrdLog.Errorf("%v", err)
return err
}
@ -159,7 +159,7 @@ func dcrdMain() error {
return nil
}
if cfg.DropExistsAddrIndex {
if err := indexers.DropExistsAddrIndex(db, interrupt); err != nil {
if err := indexers.DropExistsAddrIndex(db, ctx.Done()); err != nil {
dcrdLog.Errorf("%v", err)
return err
}
@ -167,7 +167,7 @@ func dcrdMain() error {
return nil
}
if cfg.DropCFIndex {
if err := indexers.DropCfIndex(db, interrupt); err != nil {
if err := indexers.DropCfIndex(db, ctx.Done()); err != nil {
dcrdLog.Errorf("%v", err)
return err
}
@ -178,7 +178,7 @@ func dcrdMain() error {
// Create server and start it.
lifetimeNotifier.notifyStartupEvent(lifetimeEventP2PServer)
server, err := newServer(cfg.Listeners, db, activeNetParams.Params,
cfg.DataDir, interrupt)
cfg.DataDir, ctx.Done())
if err != nil {
// TODO(oga) this logging could do with some beautifying.
dcrdLog.Errorf("Unable to start server on %v: %v",
@ -195,7 +195,7 @@ func dcrdMain() error {
server.Start()
if interruptRequested(interrupt) {
if shutdownRequested(ctx) {
return nil
}
@ -207,7 +207,7 @@ func dcrdMain() error {
// Wait until the interrupt signal is received from an OS signal or
// shutdown is requested through one of the subsystems such as the RPC
// server.
<-interrupt
<-ctx.Done()
return nil
}

View File

@ -6,6 +6,7 @@
package main
import (
"context"
"os"
"os/signal"
)
@ -18,26 +19,24 @@ 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 OS Signals such as SIGINT (Ctrl+C) and shutdown
// requests from shutdownRequestChannel. It returns a channel that is closed
// shutdownListener listens for OS Signals such as SIGINT (Ctrl+C) and shutdown
// requests from shutdownRequestChannel. It returns a context that is canceled
// when either signal is received.
func interruptListener() <-chan struct{} {
c := make(chan struct{})
func shutdownListener() context.Context {
ctx, cancel := context.WithCancel(context.Background())
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.
// Listen for initial shutdown signal and cancel the returned context.
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)
cancel()
// Listen for repeated signals and display a message so the user
// knows the shutdown is in progress and the process is not
@ -55,15 +54,15 @@ func interruptListener() <-chan struct{} {
}
}()
return c
return ctx
}
// 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 {
// shutdownRequested returns true when the context returned by shutdownListener
// was canceled. This simplifies early shutdown slightly since the caller can
// just use an if statement instead of a select.
func shutdownRequested(ctx context.Context) bool {
select {
case <-interrupted:
case <-ctx.Done():
return true
default:
}