• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
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 <stdlib.h>
6 
7 #include "base/synchronization/lock.h"
8 #include "base/threading/platform_thread.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace base {
12 
13 // Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
14 
15 class BasicLockTestThread : public PlatformThread::Delegate {
16  public:
BasicLockTestThread(Lock * lock)17   BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
18 
ThreadMain()19   virtual void ThreadMain() {
20     for (int i = 0; i < 10; i++) {
21       lock_->Acquire();
22       acquired_++;
23       lock_->Release();
24     }
25     for (int i = 0; i < 10; i++) {
26       lock_->Acquire();
27       acquired_++;
28       PlatformThread::Sleep(rand() % 20);
29       lock_->Release();
30     }
31     for (int i = 0; i < 10; i++) {
32       if (lock_->Try()) {
33         acquired_++;
34         PlatformThread::Sleep(rand() % 20);
35         lock_->Release();
36       }
37     }
38   }
39 
acquired() const40   int acquired() const { return acquired_; }
41 
42  private:
43   Lock* lock_;
44   int acquired_;
45 
46   DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
47 };
48 
TEST(LockTest,Basic)49 TEST(LockTest, Basic) {
50   Lock lock;
51   BasicLockTestThread thread(&lock);
52   PlatformThreadHandle handle = kNullThreadHandle;
53 
54   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
55 
56   int acquired = 0;
57   for (int i = 0; i < 5; i++) {
58     lock.Acquire();
59     acquired++;
60     lock.Release();
61   }
62   for (int i = 0; i < 10; i++) {
63     lock.Acquire();
64     acquired++;
65     PlatformThread::Sleep(rand() % 20);
66     lock.Release();
67   }
68   for (int i = 0; i < 10; i++) {
69     if (lock.Try()) {
70       acquired++;
71       PlatformThread::Sleep(rand() % 20);
72       lock.Release();
73     }
74   }
75   for (int i = 0; i < 5; i++) {
76     lock.Acquire();
77     acquired++;
78     PlatformThread::Sleep(rand() % 20);
79     lock.Release();
80   }
81 
82   PlatformThread::Join(handle);
83 
84   EXPECT_GE(acquired, 20);
85   EXPECT_GE(thread.acquired(), 20);
86 }
87 
88 // Test that Try() works as expected -------------------------------------------
89 
90 class TryLockTestThread : public PlatformThread::Delegate {
91  public:
TryLockTestThread(Lock * lock)92   TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
93 
ThreadMain()94   virtual void ThreadMain() {
95     got_lock_ = lock_->Try();
96     if (got_lock_)
97       lock_->Release();
98   }
99 
got_lock() const100   bool got_lock() const { return got_lock_; }
101 
102  private:
103   Lock* lock_;
104   bool got_lock_;
105 
106   DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
107 };
108 
TEST(LockTest,TryLock)109 TEST(LockTest, TryLock) {
110   Lock lock;
111 
112   ASSERT_TRUE(lock.Try());
113   // We now have the lock....
114 
115   // This thread will not be able to get the lock.
116   {
117     TryLockTestThread thread(&lock);
118     PlatformThreadHandle handle = kNullThreadHandle;
119 
120     ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
121 
122     PlatformThread::Join(handle);
123 
124     ASSERT_FALSE(thread.got_lock());
125   }
126 
127   lock.Release();
128 
129   // This thread will....
130   {
131     TryLockTestThread thread(&lock);
132     PlatformThreadHandle handle = kNullThreadHandle;
133 
134     ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
135 
136     PlatformThread::Join(handle);
137 
138     ASSERT_TRUE(thread.got_lock());
139     // But it released it....
140     ASSERT_TRUE(lock.Try());
141   }
142 
143   lock.Release();
144 }
145 
146 // Tests that locks actually exclude -------------------------------------------
147 
148 class MutexLockTestThread : public PlatformThread::Delegate {
149  public:
MutexLockTestThread(Lock * lock,int * value)150   MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
151 
152   // Static helper which can also be called from the main thread.
DoStuff(Lock * lock,int * value)153   static void DoStuff(Lock* lock, int* value) {
154     for (int i = 0; i < 40; i++) {
155       lock->Acquire();
156       int v = *value;
157       PlatformThread::Sleep(rand() % 10);
158       *value = v + 1;
159       lock->Release();
160     }
161   }
162 
ThreadMain()163   virtual void ThreadMain() {
164     DoStuff(lock_, value_);
165   }
166 
167  private:
168   Lock* lock_;
169   int* value_;
170 
171   DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
172 };
173 
TEST(LockTest,MutexTwoThreads)174 TEST(LockTest, MutexTwoThreads) {
175   Lock lock;
176   int value = 0;
177 
178   MutexLockTestThread thread(&lock, &value);
179   PlatformThreadHandle handle = kNullThreadHandle;
180 
181   ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
182 
183   MutexLockTestThread::DoStuff(&lock, &value);
184 
185   PlatformThread::Join(handle);
186 
187   EXPECT_EQ(2 * 40, value);
188 }
189 
TEST(LockTest,MutexFourThreads)190 TEST(LockTest, MutexFourThreads) {
191   Lock lock;
192   int value = 0;
193 
194   MutexLockTestThread thread1(&lock, &value);
195   MutexLockTestThread thread2(&lock, &value);
196   MutexLockTestThread thread3(&lock, &value);
197   PlatformThreadHandle handle1 = kNullThreadHandle;
198   PlatformThreadHandle handle2 = kNullThreadHandle;
199   PlatformThreadHandle handle3 = kNullThreadHandle;
200 
201   ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
202   ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
203   ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
204 
205   MutexLockTestThread::DoStuff(&lock, &value);
206 
207   PlatformThread::Join(handle1);
208   PlatformThread::Join(handle2);
209   PlatformThread::Join(handle3);
210 
211   EXPECT_EQ(4 * 40, value);
212 }
213 
214 }  // namespace base
215