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