1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/synchronization/lock.h"
6
7 #include <stdlib.h>
8
9 #include "base/compiler_specific.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/test/gtest_util.h"
12 #include "base/threading/platform_thread.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace base {
16
17 // Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
18
19 class BasicLockTestThread : public PlatformThread::Delegate {
20 public:
BasicLockTestThread(Lock * lock)21 explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
22
23 BasicLockTestThread(const BasicLockTestThread&) = delete;
24 BasicLockTestThread& operator=(const BasicLockTestThread&) = delete;
25
ThreadMain()26 void ThreadMain() override {
27 for (int i = 0; i < 10; i++) {
28 lock_->Acquire();
29 acquired_++;
30 lock_->Release();
31 }
32 for (int i = 0; i < 10; i++) {
33 lock_->Acquire();
34 acquired_++;
35 PlatformThread::Sleep(Milliseconds(rand() % 20));
36 lock_->Release();
37 }
38 for (int i = 0; i < 10; i++) {
39 if (lock_->Try()) {
40 acquired_++;
41 PlatformThread::Sleep(Milliseconds(rand() % 20));
42 lock_->Release();
43 }
44 }
45 }
46
acquired() const47 int acquired() const { return acquired_; }
48
49 private:
50 raw_ptr<Lock> lock_;
51 int acquired_;
52 };
53
TEST(LockTest,Basic)54 TEST(LockTest, Basic) {
55 Lock lock;
56 BasicLockTestThread thread(&lock);
57 PlatformThreadHandle handle;
58
59 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
60
61 int acquired = 0;
62 for (int i = 0; i < 5; i++) {
63 lock.Acquire();
64 acquired++;
65 lock.Release();
66 }
67 for (int i = 0; i < 10; i++) {
68 lock.Acquire();
69 acquired++;
70 PlatformThread::Sleep(Milliseconds(rand() % 20));
71 lock.Release();
72 }
73 for (int i = 0; i < 10; i++) {
74 if (lock.Try()) {
75 acquired++;
76 PlatformThread::Sleep(Milliseconds(rand() % 20));
77 lock.Release();
78 }
79 }
80 for (int i = 0; i < 5; i++) {
81 lock.Acquire();
82 acquired++;
83 PlatformThread::Sleep(Milliseconds(rand() % 20));
84 lock.Release();
85 }
86
87 PlatformThread::Join(handle);
88
89 EXPECT_GE(acquired, 20);
90 EXPECT_GE(thread.acquired(), 20);
91 }
92
93 // Test that Try() works as expected -------------------------------------------
94
95 class TryLockTestThread : public PlatformThread::Delegate {
96 public:
TryLockTestThread(Lock * lock)97 explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
98
99 TryLockTestThread(const TryLockTestThread&) = delete;
100 TryLockTestThread& operator=(const TryLockTestThread&) = delete;
101
ThreadMain()102 void ThreadMain() override {
103 // The local variable is required for the static analyzer to see that the
104 // lock is properly released.
105 bool got_lock = lock_->Try();
106 got_lock_ = got_lock;
107 if (got_lock)
108 lock_->Release();
109 }
110
got_lock() const111 bool got_lock() const { return got_lock_; }
112
113 private:
114 raw_ptr<Lock> lock_;
115 bool got_lock_;
116 };
117
TEST(LockTest,TryLock)118 TEST(LockTest, TryLock) {
119 Lock lock;
120
121 ASSERT_TRUE(lock.Try());
122 lock.AssertAcquired();
123
124 // This thread will not be able to get the lock.
125 {
126 TryLockTestThread thread(&lock);
127 PlatformThreadHandle handle;
128
129 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
130
131 PlatformThread::Join(handle);
132
133 ASSERT_FALSE(thread.got_lock());
134 }
135
136 lock.Release();
137
138 // This thread will....
139 {
140 TryLockTestThread thread(&lock);
141 PlatformThreadHandle handle;
142
143 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
144
145 PlatformThread::Join(handle);
146
147 ASSERT_TRUE(thread.got_lock());
148 // But it released it....
149 ASSERT_TRUE(lock.Try());
150 lock.AssertAcquired();
151 }
152
153 lock.Release();
154 }
155
156 // Tests that locks actually exclude -------------------------------------------
157
158 class MutexLockTestThread : public PlatformThread::Delegate {
159 public:
MutexLockTestThread(Lock * lock,int * value)160 MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
161
162 MutexLockTestThread(const MutexLockTestThread&) = delete;
163 MutexLockTestThread& operator=(const MutexLockTestThread&) = delete;
164
165 // Static helper which can also be called from the main thread.
DoStuff(Lock * lock,int * value)166 static void DoStuff(Lock* lock, int* value) {
167 for (int i = 0; i < 40; i++) {
168 lock->Acquire();
169 int v = *value;
170 PlatformThread::Sleep(Milliseconds(rand() % 10));
171 *value = v + 1;
172 lock->Release();
173 }
174 }
175
ThreadMain()176 void ThreadMain() override { DoStuff(lock_, value_); }
177
178 private:
179 raw_ptr<Lock> lock_;
180 raw_ptr<int> value_;
181 };
182
TEST(LockTest,MutexTwoThreads)183 TEST(LockTest, MutexTwoThreads) {
184 Lock lock;
185 int value = 0;
186
187 MutexLockTestThread thread(&lock, &value);
188 PlatformThreadHandle handle;
189
190 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
191
192 MutexLockTestThread::DoStuff(&lock, &value);
193
194 PlatformThread::Join(handle);
195
196 EXPECT_EQ(2 * 40, value);
197 }
198
TEST(LockTest,MutexFourThreads)199 TEST(LockTest, MutexFourThreads) {
200 Lock lock;
201 int value = 0;
202
203 MutexLockTestThread thread1(&lock, &value);
204 MutexLockTestThread thread2(&lock, &value);
205 MutexLockTestThread thread3(&lock, &value);
206 PlatformThreadHandle handle1;
207 PlatformThreadHandle handle2;
208 PlatformThreadHandle handle3;
209
210 ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
211 ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
212 ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
213
214 MutexLockTestThread::DoStuff(&lock, &value);
215
216 PlatformThread::Join(handle1);
217 PlatformThread::Join(handle2);
218 PlatformThread::Join(handle3);
219
220 EXPECT_EQ(4 * 40, value);
221 }
222
TEST(LockTest,AutoLockMaybe)223 TEST(LockTest, AutoLockMaybe) {
224 Lock lock;
225 {
226 AutoLockMaybe auto_lock(&lock);
227 lock.AssertAcquired();
228 }
229 EXPECT_DCHECK_DEATH(lock.AssertAcquired());
230 }
231
TEST(LockTest,AutoLockMaybeNull)232 TEST(LockTest, AutoLockMaybeNull) {
233 AutoLockMaybe auto_lock(nullptr);
234 }
235
TEST(LockTest,ReleasableAutoLockExplicitRelease)236 TEST(LockTest, ReleasableAutoLockExplicitRelease) {
237 Lock lock;
238 ReleasableAutoLock auto_lock(&lock);
239 lock.AssertAcquired();
240 auto_lock.Release();
241 EXPECT_DCHECK_DEATH(lock.AssertAcquired());
242 }
243
TEST(LockTest,ReleasableAutoLockImplicitRelease)244 TEST(LockTest, ReleasableAutoLockImplicitRelease) {
245 Lock lock;
246 {
247 ReleasableAutoLock auto_lock(&lock);
248 lock.AssertAcquired();
249 }
250 EXPECT_DCHECK_DEATH(lock.AssertAcquired());
251 }
252
253 } // namespace base
254