Repository navigation
Expand file tree
/
Copy pathclock.go
More file actions
executable file
·168 lines (136 loc) · 3.35 KB
/
Copy pathclock.go
File metadata and controls
executable file
·168 lines (136 loc) · 3.35 KB
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package m65go2
import (
_ "fmt"
"sync"
"time"
)
// Represents a clock signal for an IC. Once a Clock is started, it
// maintains a 'ticks' counters which is incremented at a specific
// interval.
type Clocker interface {
// Returns the current value of the Clocker's ticks counter.
Ticks() uint64
// Starts the clock
Start() (ticks uint64)
// Stops the clock
Stop()
// Blocks the calling thread until the given tick has arrived.
// Returns immediately if the clock has already passed the
// given tick.
Await(tick uint64) (ticks uint64)
// Increment the Clocker's ticks counter by the given amount.
Increment(amount uint64) (ticks uint64)
}
// Represents a basic clock that increments at specific intervals.
type Clock struct {
rate time.Duration
ticks uint64
ticker *time.Ticker
stopChan chan int
mutex sync.Mutex
waiting map[uint64][]chan int
}
// Returns a pointer to a new Clock which increments its ticker at
// intervals of 'rate'. The returned Clock has not been started and
// its ticks counter is zero.
func NewClock(rate time.Duration) *Clock {
return &Clock{
rate: rate,
ticks: 0,
ticker: nil,
stopChan: make(chan int),
waiting: make(map[uint64][]chan int),
}
}
func (clock *Clock) wakeWaiting() {
if Ca, ok := clock.waiting[clock.ticks]; ok {
for _, C := range Ca {
C <- 1
}
delete(clock.waiting, clock.ticks)
}
}
func (clock *Clock) maintainTime() {
for {
select {
case <-clock.stopChan:
clock.ticker.Stop()
clock.ticker = nil
return
case _ = <-clock.ticker.C:
clock.mutex.Lock()
clock.ticks++
clock.wakeWaiting()
clock.mutex.Unlock()
}
}
}
func (clock *Clock) Ticks() (ticks uint64) {
clock.mutex.Lock()
ticks = clock.ticks
clock.mutex.Unlock()
return
}
func (clock *Clock) Start() (ticks uint64) {
ticks = clock.ticks
if clock.ticker == nil {
clock.ticker = time.NewTicker(clock.rate)
go clock.maintainTime()
}
return
}
func (clock *Clock) Stop() {
if clock.ticker != nil {
clock.stopChan <- 1
}
}
func (clock *Clock) Increment(amount uint64) (ticks uint64) {
clock.mutex.Lock()
for i := uint64(1); i <= amount; i++ {
clock.ticks++
clock.wakeWaiting()
}
ticks = clock.ticks
clock.mutex.Unlock()
return
}
func (clock *Clock) Await(tick uint64) (ticks uint64) {
clock.mutex.Lock()
ticks = clock.ticks
if ticks >= tick {
clock.mutex.Unlock()
} else {
C := make(chan int, 1)
clock.waiting[tick] = append(clock.waiting[tick], C)
clock.mutex.Unlock()
<-C
}
return
}
// Represents a clock divider which divides the tick frequency of
// another Clock so that it ticks at a slower rate.
type Divider struct {
master Clocker
divisor uint64
}
// Returns a pointer to a new DividerCLock which divides the tick rate
// of 'master' Clocker by 'divisor'.
func NewDivider(master Clocker, divisor uint64) *Divider {
return &Divider{divisor: divisor, master: master}
}
func (clock *Divider) Ticks() uint64 {
return clock.master.Ticks() / clock.divisor
}
func (clock *Divider) Start() (ticks uint64) {
return clock.master.Start() / clock.divisor
}
func (clock *Divider) Stop() {
clock.master.Stop()
}
func (clock *Divider) Await(tick uint64) (ticks uint64) {
return clock.master.Await(tick*clock.divisor) / clock.divisor
}
func (clock *Divider) Increment(amount uint64) (ticks uint64) {
ticks = clock.master.Increment(amount * clock.divisor)
return
}