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