github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/signal.go (about) 1 // Copyright (c) 2013-2014 The btcsuite developers 2 // Copyright (c) 2016 The Dash 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 "os" 10 "os/signal" 11 ) 12 13 // interruptChannel is used to receive SIGINT (Ctrl+C) signals. 14 var interruptChannel chan os.Signal 15 16 // addHandlerChannel is used to add an interrupt handler to the list of handlers 17 // to be invoked on SIGINT (Ctrl+C) signals. 18 var addHandlerChannel = make(chan func()) 19 20 // signals defines the default signals to catch in order to do a proper 21 // shutdown. 22 var signals = []os.Signal{os.Interrupt} 23 24 // mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the 25 // interruptChannel and invokes the registered interruptCallbacks accordingly. 26 // It also listens for callback registration. It must be run as a goroutine. 27 func mainInterruptHandler() { 28 // interruptCallbacks is a list of callbacks to invoke when a 29 // SIGINT (Ctrl+C) is received. 30 var interruptCallbacks []func() 31 32 // isShutdown is a flag which is used to indicate whether or not 33 // the shutdown signal has already been received and hence any future 34 // attempts to add a new interrupt handler should invoke them 35 // immediately. 36 var isShutdown bool 37 38 for { 39 select { 40 case sig := <-interruptChannel: 41 // Ignore more than one shutdown signal. 42 if isShutdown { 43 btcdLog.Infof("Received signal (%s). "+ 44 "Already shutting down...", sig) 45 continue 46 } 47 48 isShutdown = true 49 btcdLog.Infof("Received signal (%s). Shutting down...", 50 sig) 51 52 // Run handlers in LIFO order. 53 for i := range interruptCallbacks { 54 idx := len(interruptCallbacks) - 1 - i 55 callback := interruptCallbacks[idx] 56 callback() 57 } 58 59 // Signal the main goroutine to shutdown. 60 go func() { 61 shutdownChannel <- struct{}{} 62 }() 63 64 case handler := <-addHandlerChannel: 65 // The shutdown signal has already been received, so 66 // just invoke and new handlers immediately. 67 if isShutdown { 68 handler() 69 } 70 71 interruptCallbacks = append(interruptCallbacks, handler) 72 } 73 } 74 } 75 76 // addInterruptHandler adds a handler to call when a SIGINT (Ctrl+C) is 77 // received. 78 func addInterruptHandler(handler func()) { 79 // Create the channel and start the main interrupt handler which invokes 80 // all other callbacks and exits if not already done. 81 if interruptChannel == nil { 82 interruptChannel = make(chan os.Signal, 1) 83 signal.Notify(interruptChannel, signals...) 84 go mainInterruptHandler() 85 } 86 87 addHandlerChannel <- handler 88 }