...
1 package regexp2
2
3 import (
4 "sync"
5 "sync/atomic"
6 "time"
7 )
8
9
10 type fasttime int64
11
12
13
14
15
16
17
18
19
20
21
22
23
24 type fastclock struct {
25
26
27
28 current atomicTime
29 clockEnd atomicTime
30
31
32
33 mu sync.Mutex
34 start time.Time
35 running bool
36 }
37
38 var fast fastclock
39
40
41 func (t fasttime) reached() bool {
42 return fast.current.read() >= t
43 }
44
45
46 func makeDeadline(d time.Duration) fasttime {
47
48
49 end := fast.current.read() + durationToTicks(d+clockPeriod)
50
51
52 if end > fast.clockEnd.read() {
53 extendClock(end)
54 }
55 return end
56 }
57
58
59 func extendClock(end fasttime) {
60 fast.mu.Lock()
61 defer fast.mu.Unlock()
62
63 if fast.start.IsZero() {
64 fast.start = time.Now()
65 }
66
67
68 if shutdown := end + durationToTicks(time.Second); shutdown > fast.clockEnd.read() {
69 fast.clockEnd.write(shutdown)
70 }
71
72
73 if !fast.running {
74 fast.running = true
75 go runClock()
76 }
77 }
78
79
80
81 func stopClock() {
82 fast.mu.Lock()
83 if fast.running {
84 fast.clockEnd.write(fasttime(0))
85 }
86 fast.mu.Unlock()
87
88
89
90 isRunning := true
91 for isRunning {
92 time.Sleep(clockPeriod / 2)
93 fast.mu.Lock()
94 isRunning = fast.running
95 fast.mu.Unlock()
96 }
97 }
98
99 func durationToTicks(d time.Duration) fasttime {
100
101
102 return fasttime(d) >> 20
103 }
104
105 const DefaultClockPeriod = 100 * time.Millisecond
106
107
108 var clockPeriod = DefaultClockPeriod
109
110 func runClock() {
111 fast.mu.Lock()
112 defer fast.mu.Unlock()
113
114 for fast.current.read() <= fast.clockEnd.read() {
115
116 fast.mu.Unlock()
117 time.Sleep(clockPeriod)
118 fast.mu.Lock()
119
120 newTime := durationToTicks(time.Since(fast.start))
121 fast.current.write(newTime)
122 }
123 fast.running = false
124 }
125
126 type atomicTime struct{ v int64 }
127
128 func (t *atomicTime) read() fasttime { return fasttime(atomic.LoadInt64(&t.v)) }
129 func (t *atomicTime) write(v fasttime) { atomic.StoreInt64(&t.v, int64(v)) }
130
View as plain text