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