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: 19 explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {} 20 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 42 int acquired() const { return acquired_; } 43 44 private: 45 Lock* lock_; 46 int acquired_; 47 48 DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); 49 }; 50 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: 94 explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {} 95 96 virtual void ThreadMain() OVERRIDE { 97 got_lock_ = lock_->Try(); 98 if (got_lock_) 99 lock_->Release(); 100 } 101 102 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 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: 152 MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {} 153 154 // Static helper which can also be called from the main thread. 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 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 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 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