decred.org/dcrwallet/v3@v3.1.0/signal.go (about) 1 // Copyright (c) 2013-2014 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "context" 9 "os" 10 "os/signal" 11 ) 12 13 // shutdownRequestChannel is used to initiate shutdown from one of the 14 // subsystems using the same code paths as when an interrupt signal is received. 15 var shutdownRequestChannel = make(chan struct{}) 16 17 // shutdownSignaled is closed whenever shutdown is invoked through an interrupt 18 // signal or from an JSON-RPC stop request. Any contexts created using 19 // withShutdownChannel are cancelled when this is closed. 20 var shutdownSignaled = make(chan struct{}) 21 22 // signals defines the signals that are handled to do a clean shutdown. 23 // Conditional compilation is used to also include SIGTERM and SIGHUP on Unix. 24 var signals = []os.Signal{os.Interrupt} 25 26 // withShutdownCancel creates a copy of a context that is cancelled whenever 27 // shutdown is invoked through an interrupt signal or from an JSON-RPC stop 28 // request. 29 func withShutdownCancel(ctx context.Context) context.Context { 30 ctx, cancel := context.WithCancel(ctx) 31 go func() { 32 <-shutdownSignaled 33 cancel() 34 }() 35 return ctx 36 } 37 38 // requestShutdown signals for starting the clean shutdown of the process 39 // through an internal component (such as through the JSON-RPC stop request). 40 func requestShutdown() { 41 shutdownRequestChannel <- struct{}{} 42 } 43 44 // shutdownListener listens for shutdown requests and cancels all contexts 45 // created from withShutdownCancel. This function never returns and is intended 46 // to be spawned in a new goroutine. 47 func shutdownListener() { 48 interruptChannel := make(chan os.Signal, 1) 49 signal.Notify(interruptChannel, signals...) 50 51 // Listen for the initial shutdown signal 52 select { 53 case sig := <-interruptChannel: 54 log.Infof("Received signal (%s). Shutting down...", sig) 55 case <-shutdownRequestChannel: 56 log.Info("Shutdown requested. Shutting down...") 57 } 58 59 // Cancel all contexts created from withShutdownCancel. 60 close(shutdownSignaled) 61 62 // Listen for any more shutdown signals and log that shutdown has already 63 // been signaled. 64 for { 65 select { 66 case <-interruptChannel: 67 case <-shutdownRequestChannel: 68 } 69 log.Info("Shutdown signaled. Already shutting down...") 70 } 71 }