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