lock_unittest.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
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
11namespace base {
12
13// Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
14
15class BasicLockTestThread : public PlatformThread::Delegate {
16 public:
17  BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
18
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
40  int acquired() const { return acquired_; }
41
42 private:
43  Lock* lock_;
44  int acquired_;
45
46  DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
47};
48
49TEST(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
90class TryLockTestThread : public PlatformThread::Delegate {
91 public:
92  TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
93
94  virtual void ThreadMain() {
95    got_lock_ = lock_->Try();
96    if (got_lock_)
97      lock_->Release();
98  }
99
100  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
109TEST(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
148class MutexLockTestThread : public PlatformThread::Delegate {
149 public:
150  MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
151
152  // Static helper which can also be called from the main thread.
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
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
174TEST(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
190TEST(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