-
Notifications
You must be signed in to change notification settings - Fork 0
/
yield.go
121 lines (92 loc) · 2.14 KB
/
yield.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
package coro
import (
"sync"
)
// TODO: using existing coroutine scheduler, something like https://github.com/nvlled/carrot/tree/main
type Yield = func()
func GoYielding(action func(yield Yield), onYielded func()) *YieldController {
ctrl := NewYieldController(onYielded)
go func() {
defer ctrl.Done()
action(ctrl.Yield)
}()
return ctrl
}
func NewYieldController(onYielded func()) *YieldController {
t := &YieldController{
stateToggledEvt: sync.Cond{L: &sync.Mutex{}},
paused: false,
finished: false,
onYielded: onYielded,
}
return t
}
type YieldController struct {
stateToggledEvt sync.Cond
paused bool
finished bool
onYielded func()
}
func (t *YieldController) Yield() {
t.stateToggledEvt.L.Lock()
defer t.stateToggledEvt.L.Unlock()
if t.paused {
panic("yielding thread expected to be not be paused")
}
if t.finished {
panic("yielding thread expected to be not be finished")
}
t.paused = true
t.stateToggledEvt.Broadcast()
if t.onYielded != nil {
t.onYielded()
}
t.stateToggledEvt.Wait()
if t.paused || t.finished {
panic("continued thread expected to not be paused or finished")
}
}
func (t *YieldController) Continue() bool {
t.stateToggledEvt.L.Lock()
defer t.stateToggledEvt.L.Unlock()
if t.finished {
return false
}
if t.paused {
t.paused = false
t.stateToggledEvt.Broadcast()
}
return true
}
func (t *YieldController) WaitUntilYielded() {
t.stateToggledEvt.L.Lock()
defer t.stateToggledEvt.L.Unlock()
if t.paused || t.finished {
return
}
t.stateToggledEvt.Wait()
if !t.finished && !t.paused {
panic("yielding thread expected to be paused or finished")
}
}
func (t *YieldController) RunUntilYielded() {
t.stateToggledEvt.L.Lock()
defer t.stateToggledEvt.L.Unlock()
if t.finished {
return
}
if t.paused {
t.paused = false
t.stateToggledEvt.Broadcast()
}
t.stateToggledEvt.Wait()
if !t.finished && !t.paused {
panic("yielding thread expected to be paused or finished")
}
}
func (t *YieldController) Done() {
t.stateToggledEvt.L.Lock()
defer t.stateToggledEvt.L.Unlock()
t.finished = true
t.stateToggledEvt.Broadcast()
}