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: 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 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: 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 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: 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 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 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