-
Notifications
You must be signed in to change notification settings - Fork 4
/
atexit.go
124 lines (98 loc) · 2.28 KB
/
atexit.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
124
/*Package atexit lets you define handlers when the program exits.
Add handlers using Register.
You must call atexit.Exit to get the handler invoked (and then terminate the program).
This package also provides replacements to log.Fatal, log.Fatalf and log.Fatalln.
Example:
package main
import (
"fmt"
"github.com/tebeka/atexit"
)
func handler() {
fmt.Println("Exiting")
}
func main() {
atexit.Register(handler)
atexit.Exit(0)
}
*/
package atexit
import (
"fmt"
"log"
"os"
"sync"
)
const (
// Version is package version
Version = "0.3.0"
)
var (
handlers = make(map[HandlerID]func())
nextHandlerID uint
handlersLock sync.RWMutex // protects the above two
once sync.Once
)
type HandlerID uint
// Cancel cancels the handler associated with id
func (id HandlerID) Cancel() error {
handlersLock.Lock()
defer handlersLock.Unlock()
_, ok := handlers[id]
if !ok {
return fmt.Errorf("handler %d not found", id)
}
delete(handlers, id)
return nil
}
// Exit runs all the atexit handlers and then terminates the program using
// os.Exit(code)
func Exit(code int) {
runHandlers()
os.Exit(code)
}
// Fatal runs all the atexit handler then calls log.Fatal (which will terminate
// the program)
func Fatal(v ...interface{}) {
runHandlers()
log.Fatal(v...)
}
// Fatalf runs all the atexit handler then calls log.Fatalf (which will
// terminate the program)
func Fatalf(format string, v ...interface{}) {
runHandlers()
log.Fatalf(format, v...)
}
// Fatalln runs all the atexit handler then calls log.Fatalln (which will
// terminate the program)
func Fatalln(v ...interface{}) {
runHandlers()
log.Fatalln(v...)
}
// Register adds a handler, call atexit.Exit to invoke all handlers.
func Register(handler func()) HandlerID {
handlersLock.Lock()
defer handlersLock.Unlock()
nextHandlerID++
id := HandlerID(nextHandlerID)
handlers[id] = handler
return id
}
func runHandler(handler func()) {
defer func() {
if err := recover(); err != nil {
fmt.Fprintln(os.Stderr, "error: atexit handler error:", err)
}
}()
handler()
}
func executeHandlers() {
handlersLock.RLock()
defer handlersLock.RUnlock()
for _, handler := range handlers {
runHandler(handler)
}
}
func runHandlers() {
once.Do(executeHandlers)
}