forked from cisco-app-networking/networkservicemesh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
single_async_operation.go
58 lines (51 loc) · 1.25 KB
/
single_async_operation.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
package utils
import (
"sync/atomic"
"time"
)
const (
notScheduled = int32(0)
running = int32(1)
scheduledAndRunning = int32(3)
)
//Operation means an object which can be executed
type Operation interface {
//Run executes operation
Run()
//Wait waits for operation completed
Wait()
}
type singleAsyncOperation struct {
body func()
state int32
}
func (s *singleAsyncOperation) Wait() {
for atomic.AddInt32(&s.state, 0) != notScheduled {
<-time.After(time.Millisecond * 25)
}
}
//NewSingleAsyncOperation creates an operation which should be invoked once by run period. Can be used in cases where required the last run.
func NewSingleAsyncOperation(body func()) Operation {
if body == nil {
panic("body can not be nil")
}
return &singleAsyncOperation{body: body, state: notScheduled}
}
func (o *singleAsyncOperation) Run() {
if !atomic.CompareAndSwapInt32(&o.state, notScheduled, running) {
if !atomic.CompareAndSwapInt32(&o.state, running, scheduledAndRunning) {
if !atomic.CompareAndSwapInt32(&o.state, notScheduled, running) {
return
}
} else {
return
}
}
go func() {
o.body()
if !atomic.CompareAndSwapInt32(&o.state, running, notScheduled) {
o.body()
atomic.StoreInt32(&o.state, notScheduled)
}
}()
}