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