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	"sync"
9	"testing"
10	"time"
11)
12
13func TestRaceMutexRWMutex(t *testing.T) {
14	var mu1 sync.Mutex
15	var mu2 sync.RWMutex
16	var x int16 = 0
17	_ = x
18	ch := make(chan bool, 2)
19	go func() {
20		mu1.Lock()
21		defer mu1.Unlock()
22		x = 1
23		ch <- true
24	}()
25	go func() {
26		mu2.Lock()
27		x = 2
28		mu2.Unlock()
29		ch <- true
30	}()
31	<-ch
32	<-ch
33}
34
35func TestNoRaceRWMutex(t *testing.T) {
36	var mu sync.RWMutex
37	var x, y int64 = 0, 1
38	_ = y
39	ch := make(chan bool, 2)
40	go func() {
41		mu.Lock()
42		defer mu.Unlock()
43		x = 2
44		ch <- true
45	}()
46	go func() {
47		mu.RLock()
48		y = x
49		mu.RUnlock()
50		ch <- true
51	}()
52	<-ch
53	<-ch
54}
55
56func TestRaceRWMutexMultipleReaders(t *testing.T) {
57	var mu sync.RWMutex
58	var x, y int64 = 0, 1
59	ch := make(chan bool, 4)
60	go func() {
61		mu.Lock()
62		defer mu.Unlock()
63		x = 2
64		ch <- true
65	}()
66	// Use three readers so that no matter what order they're
67	// scheduled in, two will be on the same side of the write
68	// lock above.
69	go func() {
70		mu.RLock()
71		y = x + 1
72		mu.RUnlock()
73		ch <- true
74	}()
75	go func() {
76		mu.RLock()
77		y = x + 2
78		mu.RUnlock()
79		ch <- true
80	}()
81	go func() {
82		mu.RLock()
83		y = x + 3
84		mu.RUnlock()
85		ch <- true
86	}()
87	<-ch
88	<-ch
89	<-ch
90	<-ch
91	_ = y
92}
93
94func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
95	var mu sync.RWMutex
96	x := int64(0)
97	ch := make(chan bool, 4)
98	go func() {
99		mu.Lock()
100		defer mu.Unlock()
101		x = 2
102		ch <- true
103	}()
104	go func() {
105		mu.RLock()
106		y := x + 1
107		_ = y
108		mu.RUnlock()
109		ch <- true
110	}()
111	go func() {
112		mu.RLock()
113		y := x + 2
114		_ = y
115		mu.RUnlock()
116		ch <- true
117	}()
118	go func() {
119		mu.RLock()
120		y := x + 3
121		_ = y
122		mu.RUnlock()
123		ch <- true
124	}()
125	<-ch
126	<-ch
127	<-ch
128	<-ch
129}
130
131func TestNoRaceRWMutexTransitive(t *testing.T) {
132	var mu sync.RWMutex
133	x := int64(0)
134	ch := make(chan bool, 2)
135	go func() {
136		mu.RLock()
137		_ = x
138		mu.RUnlock()
139		ch <- true
140	}()
141	go func() {
142		time.Sleep(1e7)
143		mu.RLock()
144		_ = x
145		mu.RUnlock()
146		ch <- true
147	}()
148	time.Sleep(2e7)
149	mu.Lock()
150	x = 42
151	mu.Unlock()
152	<-ch
153	<-ch
154}
155