From 51852570e2655791268535c5a1a0ef9f5fe7bcd6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 30 Mar 2019 21:02:52 -0500 Subject: [PATCH] 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. --- dcrd.go | 26 +++++++++++++------------- signal.go | 29 ++++++++++++++--------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/dcrd.go b/dcrd.go index cf74b938..bbedfebf 100644 --- a/dcrd.go +++ b/dcrd.go @@ -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 } diff --git a/signal.go b/signal.go index 868c8d0c..a9ac6446 100644 --- a/signal.go +++ b/signal.go @@ -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: }