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  }