Source file
src/sync/cond_test.go
1
2
3
4
5 package sync_test
6
7 import (
8 "reflect"
9 "runtime"
10 . "sync"
11 "testing"
12 "time"
13 )
14
15 func TestCondSignal(t *testing.T) {
16 var m Mutex
17 c := NewCond(&m)
18 n := 2
19 running := make(chan bool, n)
20 awake := make(chan bool, n)
21 for i := 0; i < n; i++ {
22 go func() {
23 m.Lock()
24 running <- true
25 c.Wait()
26 awake <- true
27 m.Unlock()
28 }()
29 }
30 for i := 0; i < n; i++ {
31 <-running
32 }
33 for n > 0 {
34 select {
35 case <-awake:
36 t.Fatal("goroutine not asleep")
37 default:
38 }
39 m.Lock()
40 c.Signal()
41 m.Unlock()
42 <-awake
43 select {
44 case <-awake:
45 t.Fatal("too many goroutines awake")
46 default:
47 }
48 n--
49 }
50 c.Signal()
51 }
52
53 func TestCondSignalGenerations(t *testing.T) {
54 var m Mutex
55 c := NewCond(&m)
56 n := 100
57 running := make(chan bool, n)
58 awake := make(chan int, n)
59 for i := 0; i < n; i++ {
60 go func(i int) {
61 m.Lock()
62 running <- true
63 c.Wait()
64 awake <- i
65 m.Unlock()
66 }(i)
67 if i > 0 {
68 a := <-awake
69 if a != i-1 {
70 t.Fatalf("wrong goroutine woke up: want %d, got %d", i-1, a)
71 }
72 }
73 <-running
74 m.Lock()
75 c.Signal()
76 m.Unlock()
77 }
78 }
79
80 func TestCondBroadcast(t *testing.T) {
81 var m Mutex
82 c := NewCond(&m)
83 n := 200
84 running := make(chan int, n)
85 awake := make(chan int, n)
86 exit := false
87 for i := 0; i < n; i++ {
88 go func(g int) {
89 m.Lock()
90 for !exit {
91 running <- g
92 c.Wait()
93 awake <- g
94 }
95 m.Unlock()
96 }(i)
97 }
98 for i := 0; i < n; i++ {
99 for i := 0; i < n; i++ {
100 <-running
101 }
102 if i == n-1 {
103 m.Lock()
104 exit = true
105 m.Unlock()
106 }
107 select {
108 case <-awake:
109 t.Fatal("goroutine not asleep")
110 default:
111 }
112 m.Lock()
113 c.Broadcast()
114 m.Unlock()
115 seen := make([]bool, n)
116 for i := 0; i < n; i++ {
117 g := <-awake
118 if seen[g] {
119 t.Fatal("goroutine woke up twice")
120 }
121 seen[g] = true
122 }
123 }
124 select {
125 case <-running:
126 t.Fatal("goroutine did not exit")
127 default:
128 }
129 c.Broadcast()
130 }
131
132 func TestRace(t *testing.T) {
133 x := 0
134 c := NewCond(&Mutex{})
135 done := make(chan bool)
136 go func() {
137 c.L.Lock()
138 x = 1
139 c.Wait()
140 if x != 2 {
141 t.Error("want 2")
142 }
143 x = 3
144 c.Signal()
145 c.L.Unlock()
146 done <- true
147 }()
148 go func() {
149 c.L.Lock()
150 for {
151 if x == 1 {
152 x = 2
153 c.Signal()
154 break
155 }
156 c.L.Unlock()
157 runtime.Gosched()
158 c.L.Lock()
159 }
160 c.L.Unlock()
161 done <- true
162 }()
163 go func() {
164 c.L.Lock()
165 for {
166 if x == 2 {
167 c.Wait()
168 if x != 3 {
169 t.Error("want 3")
170 }
171 break
172 }
173 if x == 3 {
174 break
175 }
176 c.L.Unlock()
177 runtime.Gosched()
178 c.L.Lock()
179 }
180 c.L.Unlock()
181 done <- true
182 }()
183 <-done
184 <-done
185 <-done
186 }
187
188 func TestCondSignalStealing(t *testing.T) {
189 for iters := 0; iters < 1000; iters++ {
190 var m Mutex
191 cond := NewCond(&m)
192
193
194 ch := make(chan struct{})
195 go func() {
196 m.Lock()
197 ch <- struct{}{}
198 cond.Wait()
199 m.Unlock()
200
201 ch <- struct{}{}
202 }()
203
204 <-ch
205 m.Lock()
206 m.Unlock()
207
208
209
210
211
212
213
214
215
216
217 done := false
218 go func() {
219 cond.Broadcast()
220 }()
221
222 go func() {
223 m.Lock()
224 for !done {
225 cond.Wait()
226 }
227 m.Unlock()
228 }()
229
230
231 select {
232 case <-ch:
233 case <-time.After(2 * time.Second):
234 t.Fatalf("First waiter didn't get broadcast.")
235 }
236
237
238
239 m.Lock()
240 done = true
241 m.Unlock()
242 cond.Broadcast()
243 }
244 }
245
246 func TestCondCopy(t *testing.T) {
247 defer func() {
248 err := recover()
249 if err == nil || err.(string) != "sync.Cond is copied" {
250 t.Fatalf("got %v, expect sync.Cond is copied", err)
251 }
252 }()
253 c := Cond{L: &Mutex{}}
254 c.Signal()
255 var c2 Cond
256 reflect.ValueOf(&c2).Elem().Set(reflect.ValueOf(&c).Elem())
257 c2.Signal()
258 }
259
260 func BenchmarkCond1(b *testing.B) {
261 benchmarkCond(b, 1)
262 }
263
264 func BenchmarkCond2(b *testing.B) {
265 benchmarkCond(b, 2)
266 }
267
268 func BenchmarkCond4(b *testing.B) {
269 benchmarkCond(b, 4)
270 }
271
272 func BenchmarkCond8(b *testing.B) {
273 benchmarkCond(b, 8)
274 }
275
276 func BenchmarkCond16(b *testing.B) {
277 benchmarkCond(b, 16)
278 }
279
280 func BenchmarkCond32(b *testing.B) {
281 benchmarkCond(b, 32)
282 }
283
284 func benchmarkCond(b *testing.B, waiters int) {
285 c := NewCond(&Mutex{})
286 done := make(chan bool)
287 id := 0
288
289 for routine := 0; routine < waiters+1; routine++ {
290 go func() {
291 for i := 0; i < b.N; i++ {
292 c.L.Lock()
293 if id == -1 {
294 c.L.Unlock()
295 break
296 }
297 id++
298 if id == waiters+1 {
299 id = 0
300 c.Broadcast()
301 } else {
302 c.Wait()
303 }
304 c.L.Unlock()
305 }
306 c.L.Lock()
307 id = -1
308 c.Broadcast()
309 c.L.Unlock()
310 done <- true
311 }()
312 }
313 for routine := 0; routine < waiters+1; routine++ {
314 <-done
315 }
316 }
317
View as plain text