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