1// Copyright 2012 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
5package race_test
6
7import (
8	"runtime"
9	"testing"
10)
11
12func TestNoRaceSelect1(t *testing.T) {
13	var x int
14	_ = x
15	compl := make(chan bool)
16	c := make(chan bool)
17	c1 := make(chan bool)
18
19	go func() {
20		x = 1
21		// At least two channels are needed because
22		// otherwise the compiler optimizes select out.
23		// See comment in runtime/select.go:^func selectgo.
24		select {
25		case c <- true:
26		case c1 <- true:
27		}
28		compl <- true
29	}()
30	select {
31	case <-c:
32	case c1 <- true:
33	}
34	x = 2
35	<-compl
36}
37
38func TestNoRaceSelect2(t *testing.T) {
39	var x int
40	_ = x
41	compl := make(chan bool)
42	c := make(chan bool)
43	c1 := make(chan bool)
44	go func() {
45		select {
46		case <-c:
47		case <-c1:
48		}
49		x = 1
50		compl <- true
51	}()
52	x = 2
53	close(c)
54	runtime.Gosched()
55	<-compl
56}
57
58func TestNoRaceSelect3(t *testing.T) {
59	var x int
60	_ = x
61	compl := make(chan bool)
62	c := make(chan bool, 10)
63	c1 := make(chan bool)
64	go func() {
65		x = 1
66		select {
67		case c <- true:
68		case <-c1:
69		}
70		compl <- true
71	}()
72	<-c
73	x = 2
74	<-compl
75}
76
77func TestNoRaceSelect4(t *testing.T) {
78	type Task struct {
79		f    func()
80		done chan bool
81	}
82
83	queue := make(chan Task)
84	dummy := make(chan bool)
85
86	go func() {
87		for {
88			select {
89			case t := <-queue:
90				t.f()
91				t.done <- true
92			}
93		}
94	}()
95
96	doit := func(f func()) {
97		done := make(chan bool, 1)
98		select {
99		case queue <- Task{f, done}:
100		case <-dummy:
101		}
102		select {
103		case <-done:
104		case <-dummy:
105		}
106	}
107
108	var x int
109	doit(func() {
110		x = 1
111	})
112	_ = x
113}
114
115func TestNoRaceSelect5(t *testing.T) {
116	test := func(sel, needSched bool) {
117		var x int
118		_ = x
119		ch := make(chan bool)
120		c1 := make(chan bool)
121
122		done := make(chan bool, 2)
123		go func() {
124			if needSched {
125				runtime.Gosched()
126			}
127			// println(1)
128			x = 1
129			if sel {
130				select {
131				case ch <- true:
132				case <-c1:
133				}
134			} else {
135				ch <- true
136			}
137			done <- true
138		}()
139
140		go func() {
141			// println(2)
142			if sel {
143				select {
144				case <-ch:
145				case <-c1:
146				}
147			} else {
148				<-ch
149			}
150			x = 1
151			done <- true
152		}()
153		<-done
154		<-done
155	}
156
157	test(true, true)
158	test(true, false)
159	test(false, true)
160	test(false, false)
161}
162
163func TestRaceSelect1(t *testing.T) {
164	var x int
165	_ = x
166	compl := make(chan bool, 2)
167	c := make(chan bool)
168	c1 := make(chan bool)
169
170	go func() {
171		<-c
172		<-c
173	}()
174	f := func() {
175		select {
176		case c <- true:
177		case c1 <- true:
178		}
179		x = 1
180		compl <- true
181	}
182	go f()
183	go f()
184	<-compl
185	<-compl
186}
187
188func TestRaceSelect2(t *testing.T) {
189	var x int
190	_ = x
191	compl := make(chan bool)
192	c := make(chan bool)
193	c1 := make(chan bool)
194	go func() {
195		x = 1
196		select {
197		case <-c:
198		case <-c1:
199		}
200		compl <- true
201	}()
202	close(c)
203	x = 2
204	<-compl
205}
206
207func TestRaceSelect3(t *testing.T) {
208	var x int
209	_ = x
210	compl := make(chan bool)
211	c := make(chan bool)
212	c1 := make(chan bool)
213	go func() {
214		x = 1
215		select {
216		case c <- true:
217		case c1 <- true:
218		}
219		compl <- true
220	}()
221	x = 2
222	select {
223	case <-c:
224	}
225	<-compl
226}
227
228func TestRaceSelect4(t *testing.T) {
229	done := make(chan bool, 1)
230	var x int
231	go func() {
232		select {
233		default:
234			x = 2
235		}
236		done <- true
237	}()
238	_ = x
239	<-done
240}
241
242// The idea behind this test:
243// there are two variables, access to one
244// of them is synchronized, access to the other
245// is not.
246// Select must (unconditionally) choose the non-synchronized variable
247// thus causing exactly one race.
248// Currently this test doesn't look like it accomplishes
249// this goal.
250func TestRaceSelect5(t *testing.T) {
251	done := make(chan bool, 1)
252	c1 := make(chan bool, 1)
253	c2 := make(chan bool)
254	var x, y int
255	go func() {
256		select {
257		case c1 <- true:
258			x = 1
259		case c2 <- true:
260			y = 1
261		}
262		done <- true
263	}()
264	_ = x
265	_ = y
266	<-done
267}
268
269// select statements may introduce
270// flakiness: whether this test contains
271// a race depends on the scheduling
272// (some may argue that the code contains
273// this race by definition)
274/*
275func TestFlakyDefault(t *testing.T) {
276	var x int
277	c := make(chan bool, 1)
278	done := make(chan bool, 1)
279	go func() {
280		select {
281		case <-c:
282			x = 2
283		default:
284			x = 3
285		}
286		done <- true
287	}()
288	x = 1
289	c <- true
290	_ = x
291	<-done
292}
293*/
294