lock_unittest.cc 6.9 KB

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