forked from blastbao/again
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinux.go
More file actions
138 lines (125 loc) · 2.83 KB
/
linux.go
File metadata and controls
138 lines (125 loc) · 2.83 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// +build !windows
package again
import (
"fmt"
"io"
"log"
"os"
"os/signal"
"strings"
"syscall"
)
const (
SIGUSR2 = syscall.SIGUSR2
)
func (a *Again) Env() (m map[string]string, err error) {
var fds []string
var names []string
var fdNames []string
a.services.Range(func(k, value interface{}) bool {
s := value.(*Service)
names = append(names, s.Name)
_, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, s.Descriptor, syscall.F_SETFD, 0)
if 0 != e1 {
err = e1
return false
}
fds = append(fds, fmt.Sprint(s.Descriptor))
fdNames = append(fdNames, s.FdName)
return true
})
if err != nil {
return
}
return map[string]string{
"GOAGAIN_FD": strings.Join(fds, ","),
"GOAGAIN_SERVICE_NAME": strings.Join(names, ","),
"GOAGAIN_NAME": strings.Join(fdNames, ","),
}, nil
}
// Kill process specified in the environment with the signal specified in the
// environment; default to SIGQUIT.
func Kill() error {
var (
pid int
sig syscall.Signal
)
_, err := fmt.Sscan(os.Getenv("GOAGAIN_PID"), &pid)
if io.EOF == err {
_, err = fmt.Sscan(os.Getenv("GOAGAIN_PPID"), &pid)
}
if nil != err {
return err
}
if _, err := fmt.Sscan(os.Getenv("GOAGAIN_SIGNAL"), &sig); nil != err {
sig = syscall.SIGQUIT
}
log.Println("sending signal", sig, "to process", pid)
return syscall.Kill(pid, sig)
}
// Wait waits for signals
func Wait(a *Again) (syscall.Signal, error) {
ch := make(chan os.Signal, 2)
signal.Notify(
ch,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGQUIT,
syscall.SIGTERM,
syscall.SIGUSR1,
syscall.SIGUSR2,
)
forked := false
for {
sig := <-ch
log.Println(sig.String())
switch sig {
// SIGHUP should reload configuration.
case syscall.SIGHUP:
if a.Hooks.OnSIGHUP != nil {
if err := a.Hooks.OnSIGHUP(a); err != nil {
log.Println("OnSIGHUP:", err)
}
}
// SIGINT should exit.
case syscall.SIGINT:
return syscall.SIGINT, nil
// SIGQUIT should exit gracefully.
case syscall.SIGQUIT:
if a.Hooks.OnSIGQUIT != nil {
if err := a.Hooks.OnSIGQUIT(a); err != nil {
log.Println("OnSIGQUIT:", err)
}
}
return syscall.SIGQUIT, nil
// SIGTERM should exit.
case syscall.SIGTERM:
if a.Hooks.OnSIGTERM != nil {
if err := a.Hooks.OnSIGHUP(a); err != nil {
log.Println("OnSIGTERM:", err)
}
}
return syscall.SIGTERM, nil
// SIGUSR1 should reopen logs.
case syscall.SIGUSR1:
if a.Hooks.OnSIGUSR1 != nil {
if err := a.Hooks.OnSIGUSR1(a); err != nil {
log.Println("OnSIGUSR1:", err)
}
}
// SIGUSR2 forks and re-execs the first time it is received and execs
// without forking from then on.
case syscall.SIGUSR2:
if OnForkHook != nil {
OnForkHook()
}
if forked {
return syscall.SIGUSR2, nil
}
forked = true
if err := ForkExec(a); nil != err {
return syscall.SIGUSR2, err
}
}
}
}