github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/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  }