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