decred.org/dcrdex@v1.0.5/server/cmd/dcrdex/signal.go (about) 1 // Copyright (c) 2018-2020, The Decred developers 2 // Copyright (c) 2013-2014, The btcsuite developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package main 7 8 import ( 9 "context" 10 "fmt" 11 "os" 12 "os/signal" 13 ) 14 15 // shutdownRequested checks if the Done channel of the given context has been 16 // closed. This could indicate cancellation, expiration, or deadline expiry. But 17 // when called for the context provided by withShutdownCancel, it indicates if 18 // shutdown has been requested (i.e. via os.Interrupt or requestShutdown). 19 func shutdownRequested(ctx context.Context) bool { 20 select { 21 case <-ctx.Done(): 22 return true 23 default: 24 return false 25 } 26 } 27 28 var ( 29 // shutdownRequest is used to initiate shutdown from one of the subsystems 30 // using the same code paths as when an interrupt signal is received. 31 shutdownRequest = make(chan struct{}) 32 // shutdownSignal is closed whenever shutdown is invoked through an 33 // interrupt signal or via requestShutdown. Any contexts created using 34 // withShutdownChannel are canceled when this is closed. 35 shutdownSignal = make(chan struct{}) 36 ) 37 38 // withShutdownCancel creates a copy of a context that is canceled whenever 39 // shutdown is invoked through an interrupt signal or from an JSON-RPC stop 40 // request. 41 func withShutdownCancel(ctx context.Context) context.Context { 42 ctx, cancel := context.WithCancel(ctx) 43 go func() { 44 <-shutdownSignal 45 cancel() 46 }() 47 return ctx 48 } 49 50 // requestShutdown signals for starting the clean shutdown of the process 51 // through an internal component. 52 func requestShutdown() { 53 shutdownRequest <- struct{}{} 54 } 55 56 // shutdownListener listens for shutdown requests and cancels all contexts 57 // created from withShutdownCancel. This function never returns and is intended 58 // to be spawned in a new goroutine. 59 func shutdownListener() { 60 interruptChannel := make(chan os.Signal, 1) 61 signal.Notify(interruptChannel, os.Interrupt) 62 63 // Listen for the initial shutdown signal. 64 select { 65 case sig := <-interruptChannel: 66 fmt.Printf("Received signal (%s). Shutting down...\n", sig) 67 case <-shutdownRequest: 68 fmt.Println("Shutdown requested. Shutting down...") 69 } 70 71 // Cancel all contexts created from withShutdownCancel. 72 close(shutdownSignal) 73 74 // Listen for any more shutdown signals and log that shutdown has already 75 // been signaled. 76 for { 77 select { 78 case <-interruptChannel: 79 case <-shutdownRequest: 80 } 81 log.Info("Shutdown signaled. Already shutting down...") 82 } 83 }