OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / database / cmd / dbtool / signal.go
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 }