2018-23-01 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libgo / go / sync / cond_test.go
blob9019f8f102827ff57636acbee43a41f5209dce9a
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 package sync_test
6 import (
7 . "sync"
9 "runtime"
10 "testing"
11 "time"
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 }()
29 for i := 0; i < n; i++ {
30 <-running // Wait for everyone to run.
32 for n > 0 {
33 select {
34 case <-awake:
35 t.Fatal("goroutine not asleep")
36 default:
38 m.Lock()
39 c.Signal()
40 m.Unlock()
41 <-awake // Will deadlock if no goroutine wakes up
42 select {
43 case <-awake:
44 t.Fatal("too many goroutines awake")
45 default:
47 n--
49 c.Signal()
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)
72 <-running
73 m.Lock()
74 c.Signal()
75 m.Unlock()
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
94 m.Unlock()
95 }(i)
97 for i := 0; i < n; i++ {
98 for i := 0; i < n; i++ {
99 <-running // Will deadlock unless n are running.
101 if i == n-1 {
102 m.Lock()
103 exit = true
104 m.Unlock()
106 select {
107 case <-awake:
108 t.Fatal("goroutine not asleep")
109 default:
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")
120 seen[g] = true
123 select {
124 case <-running:
125 t.Fatal("goroutine did not exit")
126 default:
128 c.Broadcast()
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")
142 x = 3
143 c.Signal()
144 c.L.Unlock()
145 done <- true
147 go func() {
148 c.L.Lock()
149 for {
150 if x == 1 {
151 x = 2
152 c.Signal()
153 break
155 c.L.Unlock()
156 runtime.Gosched()
157 c.L.Lock()
159 c.L.Unlock()
160 done <- true
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")
170 break
172 if x == 3 {
173 break
175 c.L.Unlock()
176 runtime.Gosched()
177 c.L.Lock()
179 c.L.Unlock()
180 done <- true
182 <-done
183 <-done
184 <-done
187 func TestCondSignalStealing(t *testing.T) {
188 for iters := 0; iters < 1000; iters++ {
189 var m Mutex
190 cond := NewCond(&m)
192 // Start a waiter.
193 ch := make(chan struct{})
194 go func() {
195 m.Lock()
196 ch <- struct{}{}
197 cond.Wait()
198 m.Unlock()
200 ch <- struct{}{}
203 <-ch
204 m.Lock()
205 m.Unlock()
207 // We know that the waiter is in the cond.Wait() call because we
208 // synchronized with it, then acquired/released the mutex it was
209 // holding when we synchronized.
211 // Start two goroutines that will race: one will broadcast on
212 // the cond var, the other will wait on it.
214 // The new waiter may or may not get notified, but the first one
215 // has to be notified.
216 done := false
217 go func() {
218 cond.Broadcast()
221 go func() {
222 m.Lock()
223 for !done {
224 cond.Wait()
226 m.Unlock()
229 // Check that the first waiter does get signaled.
230 select {
231 case <-ch:
232 case <-time.After(2 * time.Second):
233 t.Fatalf("First waiter didn't get broadcast.")
236 // Release the second waiter in case it didn't get the
237 // broadcast.
238 m.Lock()
239 done = true
240 m.Unlock()
241 cond.Broadcast()
245 func TestCondCopy(t *testing.T) {
246 defer func() {
247 err := recover()
248 if err == nil || err.(string) != "sync.Cond is copied" {
249 t.Fatalf("got %v, expect sync.Cond is copied", err)
252 c := Cond{L: &Mutex{}}
253 c.Signal()
254 c2 := c
255 c2.Signal()
258 func BenchmarkCond1(b *testing.B) {
259 benchmarkCond(b, 1)
262 func BenchmarkCond2(b *testing.B) {
263 benchmarkCond(b, 2)
266 func BenchmarkCond4(b *testing.B) {
267 benchmarkCond(b, 4)
270 func BenchmarkCond8(b *testing.B) {
271 benchmarkCond(b, 8)
274 func BenchmarkCond16(b *testing.B) {
275 benchmarkCond(b, 16)
278 func BenchmarkCond32(b *testing.B) {
279 benchmarkCond(b, 32)
282 func benchmarkCond(b *testing.B, waiters int) {
283 c := NewCond(&Mutex{})
284 done := make(chan bool)
285 id := 0
287 for routine := 0; routine < waiters+1; routine++ {
288 go func() {
289 for i := 0; i < b.N; i++ {
290 c.L.Lock()
291 if id == -1 {
292 c.L.Unlock()
293 break
295 id++
296 if id == waiters+1 {
297 id = 0
298 c.Broadcast()
299 } else {
300 c.Wait()
302 c.L.Unlock()
304 c.L.Lock()
305 id = -1
306 c.Broadcast()
307 c.L.Unlock()
308 done <- true
311 for routine := 0; routine < waiters+1; routine++ {
312 <-done