/
core.go
123 lines (101 loc) · 2.55 KB
/
core.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package core
import (
"os"
"os/signal"
"sync"
"syscall"
"github.com/emccode/libstorage/api/context"
apitypes "github.com/emccode/libstorage/api/types"
)
var (
// Version of REX-Ray.
Version *apitypes.VersionInfo
)
type osString string
func (o osString) String() string {
switch o {
case "linux":
return "Linux"
case "darwin":
return "Darwin"
case "windows":
return "Windows"
default:
return string(o)
}
}
type archString string
func (a archString) String() string {
switch a {
case "386":
return "i386"
case "amd64":
return "x86_64"
default:
return string(a)
}
}
// SignalHandlerFunc is a function that can be registered with
// `core.RegisterSignalHandler` to receive a callback when the process receives
// a signal.
type SignalHandlerFunc func(ctx apitypes.Context, s os.Signal)
var (
sigHandlers []SignalHandlerFunc
sigHandlersRWL = &sync.RWMutex{}
)
// RegisterSignalHandler registers a SignalHandlerFunc.
func RegisterSignalHandler(f SignalHandlerFunc) {
sigHandlersRWL.Lock()
defer sigHandlersRWL.Unlock()
sigHandlers = append(sigHandlers, f)
}
type signalContextKeyType int
const signalContextKey signalContextKeyType = 0
func (k signalContextKeyType) String() string {
return "signal"
}
// TrapSignals tells the process to trap incoming process signals.
func TrapSignals(ctx apitypes.Context) {
context.RegisterCustomKey(signalContextKey, context.CustomLoggerKey)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc)
go func() {
for s := range sigc {
ctx := ctx.WithValue(signalContextKey, s.String())
if ok, graceful := IsExitSignal(s); ok && !graceful {
ctx.Error("received signal; aborting")
os.Exit(1)
}
func() {
sigHandlersRWL.RLock()
defer sigHandlersRWL.RUnlock()
// execute the signal handlers in reverse order. the first
// one registered should be executed last as it was registered
// the earliest
for i := len(sigHandlers) - 1; i >= 0; i-- {
sigHandlers[i](ctx, s)
}
}()
if ok, graceful := IsExitSignal(s); ok && graceful {
ctx.Error("received signal; shutting down")
os.Exit(0)
}
}
}()
}
// IsExitSignal returns a flag indicating whether a signal is SIGKILL, SIGHUP,
// SIGINT, SIGTERM, or SIGQUIT. The second return value is whether it is a
// graceful exit. This flag is true for SIGHUP, SIGINT, and SIGQUIT.
func IsExitSignal(s os.Signal) (bool, bool) {
switch s {
case syscall.SIGKILL,
syscall.SIGTERM:
return true, false
case syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGQUIT:
return true, true
default:
return false, false
}
}