-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdefers.go
77 lines (69 loc) · 1.52 KB
/
defers.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
// Package defers handles program-wide defers.
//
// Defers are executed when defers.Exit() is called or when an interrupt signal
// is caught, whichever happens first.
//
// If an interrupt signal is caught, the program will exit with a status of
// 128 plus the signal number. In the event the signal number cannot be
// determined, the program will exit with exit status 1.
package defers
import "os"
var (
exit = os.Exit
exitc = make(chan int)
deferc = make(chan defunc)
runc = make(chan chan struct{})
sigc = make(chan os.Signal, 1)
)
type defunc struct {
fn func()
added chan struct{}
}
func init() {
go func() {
var defers []func()
for {
select {
case code := <-exitc:
for _, f := range defers {
f()
}
exit(code)
case d := <-deferc:
defers = append([]func(){d.fn}, defers...)
d.added <- struct{}{}
case c := <-runc:
for _, f := range defers {
f()
}
defers = []func(){}
c <- struct{}{}
}
}
}()
go func() { exitc <- signalCode(<-sigc) }()
notify(sigc)
}
// Add adds a function to the front of the defer list.
func Add(f func()) {
d := defunc{f, make(chan struct{})}
deferc <- d
<-d.added
}
// Exit runs all defers, then exits the program.
func Exit(code int) {
exitc <- code
select {}
}
// Run runs defers and clears the defer list.
// For best results, defer Run in main().
//
// func main() {
// defer defers.Run()
// panic("error") // Will run defers before exiting the program.
// }
func Run() {
c := make(chan struct{})
runc <- c
<-c
}