forked from NebulousLabs/Sia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtryrwmutex_test.go
194 lines (174 loc) · 3.95 KB
/
tryrwmutex_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package sync
import (
"runtime"
"sync"
"testing"
)
// TestTryRWMutexBasicMutex verifies that Lock and Unlock work the same as a
// normal mutex would.
func TestTryRWMutexBasicMutex(t *testing.T) {
// Check that two calls to lock will execute in the correct order.
var tm TryRWMutex
var data int
tm.Lock()
go func() {
data = 15
tm.Unlock()
}()
tm.Lock()
if data != 15 {
t.Error("Locking did not safely protect the data")
}
tm.Unlock()
}
// TestTryRWMutexConcurrentLocking checks that doing lots of concurrent locks
// is handled as expected.
func TestTryRWMutexConcurrentLocking(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
// Try executing multiple additions concurrently.
var tm TryRWMutex
var data int
var wg sync.WaitGroup
for i := 0; i < 250; i++ {
wg.Add(1)
go func() {
tm.Lock()
data++
tm.Unlock()
wg.Done()
}()
}
wg.Wait()
if data != 250 {
t.Error("Locking did not safely protect the data")
}
}
// TestTryRWMutexBasicTryLock checks that a TryLock will succeed if nobody is
// holding a lock, and will fail if the lock is being held.
func TestTryRWMutexBasicTryLock(t *testing.T) {
// Lock and then TryLock.
var tm TryRWMutex
tm.Lock()
if tm.TryLock() {
t.Error("TryLock should have failed")
}
tm.Unlock()
tm.Lock()
tm.Unlock()
// TryLock and then TryLock.
if !tm.TryLock() {
t.Error("Could not get a blank lock")
}
if tm.TryLock() {
t.Error("should not have been able to get the lock")
}
tm.Unlock()
}
// TestTryRWMutexConcurrentTries attempts to grab locks from many threads,
// giving the race detector a chance to detect any issues.
func TestTryRWMutexConncurrentTries(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
// Try executing multiple additions concurrently.
var tm TryRWMutex
var data int
var wg sync.WaitGroup
for i := 0; i < 250; i++ {
wg.Add(1)
go func() {
for !tm.TryLock() {
}
data++
tm.Unlock()
wg.Done()
}()
}
wg.Wait()
if data != 250 {
t.Error("Locking did not safely protect the data")
}
}
// TestTryRWMutexReadAvailable will try to acquire a read lock on the mutex
// when it is supposed to be available.
func TestTryRWMutexReadAvailable(t *testing.T) {
var tm TryRWMutex
if !tm.TryRLock() {
t.Fatal("Unable to get readlock on a fresh TryRWMutex")
}
// Grab the lock and increment the data in a goroutine.
var data int
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
tm.Lock()
data++
tm.Unlock()
}()
runtime.Gosched()
go func() {
defer wg.Done()
tm.Lock()
data++
tm.Unlock()
}()
runtime.Gosched()
// Read the data, readlock should be held.
if data != 0 {
t.Fatal("Data should not have changed while under readlock")
}
// Release the lock and wait for the other locks to finish their
// modifications.
tm.RUnlock()
wg.Wait()
// Try to grab another readlock. It should succeed. The data should have
// changed.
if !tm.TryRLock() {
t.Fatal("Unable to get readlock on available TryRWMutex")
}
if data != 2 {
t.Error("Data does not seem to have been altered correctly")
}
tm.RUnlock()
}
// TestTryRWMutexReadUnavailable will try to acquire a read lock on the mutex
// when it is supposed to be available.
func TestTryRWMutexReadUnavailable(t *testing.T) {
var tm TryRWMutex
if !tm.TryRLock() {
t.Fatal("Unable to get readlock on a fresh TryRWMutex")
}
// Grab the lock and increment the data in a goroutine.
var data int
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
tm.Lock()
data++
tm.Unlock()
}()
runtime.Gosched()
go func() {
defer wg.Done()
tm.Lock()
data++
tm.Unlock()
}()
runtime.Gosched()
// Read the data, readlock should be held.
if data != 0 {
t.Fatal("Data should not have changed while under readlock")
}
// Try to grab another readlock. It should not succeed.
if tm.TryRLock() {
t.Fatal("Able to get readlock on available TryRWMutex")
}
// Release the lock and wait for the other locks to finish their
// modifications.
tm.RUnlock()
wg.Wait()
}