diff --git a/dcrpool.go b/dcrpool.go index 2d5f01a0..36782393 100644 --- a/dcrpool.go +++ b/dcrpool.go @@ -5,14 +5,12 @@ package main import ( - "context" "errors" "fmt" "math" "net/http" _ "net/http/pprof" "os" - "os/signal" "path/filepath" "runtime" "strings" @@ -23,10 +21,6 @@ import ( "github.com/decred/dcrpool/pool" ) -// signals defines the signals that are handled to do a clean shutdown. -// Conditional compilation is used to also include SIGTERM and SIGHUP on Unix. -var signals = []os.Signal{os.Interrupt} - // newHub returns a new pool hub configured with the provided details that is // ready to connect to a consensus daemon and wallet in the case of publicly // available pools. @@ -115,10 +109,6 @@ func newGUI(cfg *config, hub *pool.Hub) (*gui.GUI, error) { // realMain is the real main function for dcrpool. It is necessary to work // around the fact that deferred functions do not run when os.Exit() is called. func realMain() error { - // Listen for interrupt signals. - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, signals...) - // Load configuration and parse command line. This also initializes // logging and configures it accordingly. appName := filepath.Base(os.Args[0]) @@ -139,8 +129,12 @@ func realMain() error { } }() + // Get a context whose done channel will be closed when a shutdown signal + // has been triggered from an OS signal such as SIGINT (Ctrl+C) or when the + // returned cancel function is manually called. + // // Primary context that controls the entire process. - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := shutdownListener() defer mpLog.Info("Shutdown complete") // Show version and home dir at startup. @@ -179,16 +173,6 @@ func realMain() error { }() } - go func() { - select { - case <-ctx.Done(): - return - - case <-interrupt: - cancel() - } - }() - // Create a hub instance and attempt to perform initial connection and work // acquisition. hub, err := newHub(cfg, db) diff --git a/signal.go b/signal.go new file mode 100644 index 00000000..5de202a4 --- /dev/null +++ b/signal.go @@ -0,0 +1,44 @@ +// Copyright (c) 2015-2023 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package main + +import ( + "context" + "os" + "os/signal" +) + +// 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} + +// shutdownListener returns a context whose done channel will be closed when OS +// signals such as SIGINT (Ctrl+C) are received along with a cancel function +// that may be used to manually close the channel. +func shutdownListener() (context.Context, context.CancelFunc) { + ctx, cancel := context.WithCancel(context.Background()) + go func() { + interruptChannel := make(chan os.Signal, 1) + signal.Notify(interruptChannel, interruptSignals...) + + // Listen for initial shutdown signal and cancel the context or + // fallthrough if the caller manually cancels the context. + select { + case sig := <-interruptChannel: + mpLog.Infof("Received signal (%s). Shutting down...", sig) + cancel() + case <-ctx.Done(): + } + + // Listen for repeated signals and display a message so the user knows + // the shutdown is in progress and the process is not hung. + for { + sig := <-interruptChannel + mpLog.Infof("Received signal (%s). Already shutting down...", sig) + } + }() + + return ctx, cancel +} diff --git a/signal_syscall.go b/signal_syscall.go new file mode 100644 index 00000000..850f3e5a --- /dev/null +++ b/signal_syscall.go @@ -0,0 +1,15 @@ +// Copyright (c) 2021-2023 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. +// +//go:build windows || aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || linux || netbsd || openbsd || solaris + +package main + +import ( + "syscall" +) + +func init() { + interruptSignals = append(interruptSignals, syscall.SIGTERM, syscall.SIGHUP) +} diff --git a/signal_unix.go b/signal_unix.go deleted file mode 100644 index 98e1ba6d..00000000 --- a/signal_unix.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2016 The btcsuite developers -// Copyright (c) 2021-2022 The Decred developers -// Use of this source code is governed by an ISC -// license that can be found in the LICENSE file. - -//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris - -package main - -import ( - "os" - "syscall" -) - -func init() { - signals = []os.Signal{ - os.Interrupt, - syscall.SIGTERM, - syscall.SIGHUP, - } -}