decred.org/dcrwallet/v3@v3.1.0/signal.go (about)

     1  // Copyright (c) 2013-2014 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  	"context"
     9  	"os"
    10  	"os/signal"
    11  )
    12  
    13  // shutdownRequestChannel is used to initiate shutdown from one of the
    14  // subsystems using the same code paths as when an interrupt signal is received.
    15  var shutdownRequestChannel = make(chan struct{})
    16  
    17  // shutdownSignaled is closed whenever shutdown is invoked through an interrupt
    18  // signal or from an JSON-RPC stop request.  Any contexts created using
    19  // withShutdownChannel are cancelled when this is closed.
    20  var shutdownSignaled = make(chan struct{})
    21  
    22  // signals defines the signals that are handled to do a clean shutdown.
    23  // Conditional compilation is used to also include SIGTERM and SIGHUP on Unix.
    24  var signals = []os.Signal{os.Interrupt}
    25  
    26  // withShutdownCancel creates a copy of a context that is cancelled whenever
    27  // shutdown is invoked through an interrupt signal or from an JSON-RPC stop
    28  // request.
    29  func withShutdownCancel(ctx context.Context) context.Context {
    30  	ctx, cancel := context.WithCancel(ctx)
    31  	go func() {
    32  		<-shutdownSignaled
    33  		cancel()
    34  	}()
    35  	return ctx
    36  }
    37  
    38  // requestShutdown signals for starting the clean shutdown of the process
    39  // through an internal component (such as through the JSON-RPC stop request).
    40  func requestShutdown() {
    41  	shutdownRequestChannel <- struct{}{}
    42  }
    43  
    44  // shutdownListener listens for shutdown requests and cancels all contexts
    45  // created from withShutdownCancel.  This function never returns and is intended
    46  // to be spawned in a new goroutine.
    47  func shutdownListener() {
    48  	interruptChannel := make(chan os.Signal, 1)
    49  	signal.Notify(interruptChannel, signals...)
    50  
    51  	// Listen for the initial shutdown signal
    52  	select {
    53  	case sig := <-interruptChannel:
    54  		log.Infof("Received signal (%s).  Shutting down...", sig)
    55  	case <-shutdownRequestChannel:
    56  		log.Info("Shutdown requested.  Shutting down...")
    57  	}
    58  
    59  	// Cancel all contexts created from withShutdownCancel.
    60  	close(shutdownSignaled)
    61  
    62  	// Listen for any more shutdown signals and log that shutdown has already
    63  	// been signaled.
    64  	for {
    65  		select {
    66  		case <-interruptChannel:
    67  		case <-shutdownRequestChannel:
    68  		}
    69  		log.Info("Shutdown signaled.  Already shutting down...")
    70  	}
    71  }