From 0ae6dec4f3d6e10efb47d24ffb15d8cb2218f09a Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Thu, 14 Jun 2018 20:15:19 -0700 Subject: [PATCH] signal/signal: creates package for monitoring of OS signals --- signal.go | 96 -------------------------------------------- signal/signal.go | 101 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 96 deletions(-) delete mode 100644 signal.go create mode 100644 signal/signal.go diff --git a/signal.go b/signal.go deleted file mode 100644 index c409590b..00000000 --- a/signal.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2013-2017 The btcsuite developers -// Copyright (c) 2015-2016 The Decred developers -// Heavily inspired by https://github.com/btcsuite/btcd/blob/master/signal.go -// Copyright (C) 2015-2017 The Lightning Network Developers - -package main - -import ( - "os" - "os/signal" -) - -// interruptChannel is used to receive SIGINT (Ctrl+C) signals. -var interruptChannel chan os.Signal - -// shutdownRequestChannel is used to request the daemon to shutdown gracefully, -// similar to when receiving SIGINT. -var shutdownRequestChannel = make(chan struct{}) - -// addHandlerChannel is used to add an interrupt handler to the list of handlers -// to be invoked on SIGINT (Ctrl+C) signals and shutdown. -var addHandlerChannel = make(chan func()) - -// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the -// interruptChannel and shutdown requests on the shutdownRequestChannel, and -// invokes the registered interruptCallbacks accordingly. It also listens for -// callback registration. -// It must be run as a goroutine. -func mainInterruptHandler() { - // interruptCallbacks is a list of callbacks to invoke when a - // SIGINT (Ctrl+C) or a shutdown request is received. - var interruptCallbacks []func() - - // isShutdown is a flag which is used to indicate whether or not - // the shutdown signal has already been received and hence any future - // attempts to add a new interrupt handler should invoke them - // immediately. - var isShutdown bool - - // shutdown invokes the registered interrupt handlers, then signals the - // shutdownChannel. - shutdown := func() { - // Ignore more than one shutdown signal. - if isShutdown { - ltndLog.Infof("Already shutting down...") - return - } - isShutdown = true - ltndLog.Infof("Shutting down...") - - // Execute the interrupt callbacks in FIFO order. - for _, callback := range interruptCallbacks { - callback() - } - - // Signal the main goroutine to shutdown. - go func() { - shutdownChannel <- struct{}{} - }() - } - - for { - select { - case <-interruptChannel: - ltndLog.Infof("Received SIGINT (Ctrl+C).") - shutdown() - - case <-shutdownRequestChannel: - ltndLog.Infof("Received shutdown request.") - shutdown() - - case handler := <-addHandlerChannel: - // The shutdown signal has already been received, so - // just invoke any new handlers immediately. - if isShutdown { - handler() - } - - interruptCallbacks = append(interruptCallbacks, handler) - } - } -} - -// addInterruptHandler adds a handler to call when a SIGINT (Ctrl+C) or a -// shutdown request is received. -func addInterruptHandler(handler func()) { - // Create the channel and start the main interrupt handler which invokes - // all other callbacks and exits if not already done. - if interruptChannel == nil { - interruptChannel = make(chan os.Signal, 1) - signal.Notify(interruptChannel, os.Interrupt) - go mainInterruptHandler() - } - - addHandlerChannel <- handler -} diff --git a/signal/signal.go b/signal/signal.go new file mode 100644 index 00000000..f1a5b978 --- /dev/null +++ b/signal/signal.go @@ -0,0 +1,101 @@ +// Copyright (c) 2013-2017 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// Heavily inspired by https://github.com/btcsuite/btcd/blob/master/signal.go +// Copyright (C) 2015-2017 The Lightning Network Developers + +package signal + +import ( + "os" + "os/signal" +) + +var ( + // interruptChannel is used to receive SIGINT (Ctrl+C) signals. + interruptChannel = make(chan os.Signal, 1) + + // shutdownRequestChannel is used to request the daemon to shutdown + // gracefully, similar to when receiving SIGINT. + shutdownRequestChannel = make(chan struct{}) + + // quit is closed when instructing the main interrupt handler to exit. + quit = make(chan struct{}) + + // shutdownChannel is closed once the main interrupt handler exits. + shutdownChannel = make(chan struct{}) +) + +func init() { + signal.Notify(interruptChannel, os.Interrupt) + go mainInterruptHandler() +} + +// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the +// interruptChannel and shutdown requests on the shutdownRequestChannel, and +// invokes the registered interruptCallbacks accordingly. It also listens for +// callback registration. +// It must be run as a goroutine. +func mainInterruptHandler() { + // isShutdown is a flag which is used to indicate whether or not + // the shutdown signal has already been received and hence any future + // attempts to add a new interrupt handler should invoke them + // immediately. + var isShutdown bool + + // shutdown invokes the registered interrupt handlers, then signals the + // shutdownChannel. + shutdown := func() { + // Ignore more than one shutdown signal. + if isShutdown { + log.Infof("Already shutting down...") + return + } + isShutdown = true + log.Infof("Shutting down...") + + // Signal the main interrupt handler to exit, and stop accept + // post-facto requests. + close(quit) + } + + for { + select { + case <-interruptChannel: + log.Infof("Received SIGINT (Ctrl+C).") + shutdown() + + case <-shutdownRequestChannel: + log.Infof("Received shutdown request.") + shutdown() + + case <-quit: + log.Infof("Gracefully shutting down.") + close(shutdownChannel) + return + } + } +} + +// Alive returns true if the main interrupt handler has not been killed. +func Alive() bool { + select { + case <-quit: + return false + default: + return true + } +} + +// RequestShutdown initiates a graceful shutdown from the application. +func RequestShutdown() { + select { + case shutdownRequestChannel <- struct{}{}: + case <-quit: + } +} + +// ShutdownChannel returns the channel that will be closed once the main +// interrupt handler has exited. +func ShutdownChannel() <-chan struct{} { + return shutdownChannel +}