-
Notifications
You must be signed in to change notification settings - Fork 4
/
flag_startstop.go
123 lines (104 loc) · 2.23 KB
/
flag_startstop.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 atomickit
import (
"runtime"
"sync/atomic"
"time"
)
const (
starting = -1
active = 1
stopping = 2
stopped = 3
)
type StartStopFlag struct {
done int32
}
func (p *StartStopFlag) IsActive() bool {
return atomic.LoadInt32(&p.done) == active
}
func (p *StartStopFlag) IsStarting() bool {
return atomic.LoadInt32(&p.done) < 0
}
func (p *StartStopFlag) WasStarted() bool {
return atomic.LoadInt32(&p.done) != 0
}
func (p *StartStopFlag) WasStopped() bool {
return atomic.LoadInt32(&p.done) >= stopping
}
func (p *StartStopFlag) IsStopping() bool {
return atomic.LoadInt32(&p.done) == stopping
}
func (p *StartStopFlag) IsStopped() bool {
return atomic.LoadInt32(&p.done) == stopped
}
func (p *StartStopFlag) Status() (isActive, wasStarted bool) {
n := atomic.LoadInt32(&p.done)
return n == active, n != 0
}
func (p *StartStopFlag) DoStart(f func()) bool {
if !atomic.CompareAndSwapInt32(&p.done, 0, starting) {
return false
}
p.doSlow(f, active)
return true
}
func (p *StartStopFlag) DoStop(f func()) bool {
if !atomic.CompareAndSwapInt32(&p.done, active, stopping) {
return false
}
p.doSlow(f, stopped)
return true
}
func (p *StartStopFlag) DoDiscard(discardFn, stopFn func()) bool {
for i := uint(0); ; i++ {
switch atomic.LoadInt32(&p.done) {
case 0:
if atomic.CompareAndSwapInt32(&p.done, 0, stopping) {
p.doSlow(discardFn, stopped)
return true
}
case active:
return p.DoStop(stopFn)
case starting:
spinWait(int(i))
default:
return false
}
}
}
func spinWait(spinCount int) {
switch {
case spinCount < 10:
runtime.Gosched()
case spinCount < 100:
time.Sleep(time.Microsecond)
default:
time.Sleep(time.Millisecond)
}
}
func (p *StartStopFlag) DoDiscardByOne(fn func(wasStarted bool)) bool {
if fn == nil {
return p.DoDiscard(nil, nil)
}
return p.DoDiscard(func() {
fn(false)
}, func() {
fn(true)
})
}
func (p *StartStopFlag) Start() bool {
return atomic.CompareAndSwapInt32(&p.done, 0, active)
}
func (p *StartStopFlag) Stop() bool {
return atomic.CompareAndSwapInt32(&p.done, active, stopped)
}
func (p *StartStopFlag) doSlow(f func(), status int32) {
upd := int32(stopped)
defer func() {
atomic.StoreInt32(&p.done, upd)
}()
if f != nil {
f()
}
upd = status
}