partition_lock_unittest.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // Copyright 2020 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/allocator/partition_allocator/partition_lock.h"
  5. #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
  6. #include "base/allocator/partition_allocator/partition_alloc_base/migration_adapter.h"
  7. #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
  8. #include "base/allocator/partition_allocator/partition_alloc_base/threading/platform_thread_for_testing.h"
  9. #include "base/allocator/partition_allocator/partition_alloc_base/time/time.h"
  10. #include "build/build_config.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. namespace partition_alloc::internal {
  13. TEST(PartitionAllocLockTest, Simple) {
  14. Lock lock;
  15. lock.Acquire();
  16. lock.Release();
  17. }
  18. namespace {
  19. Lock g_lock;
  20. } // namespace
  21. TEST(PartitionAllocLockTest, StaticLockStartsUnlocked) {
  22. g_lock.Acquire();
  23. g_lock.Release();
  24. }
  25. namespace {
  26. class ThreadDelegateForContended
  27. : public base::PlatformThreadForTesting::Delegate {
  28. public:
  29. explicit ThreadDelegateForContended(Lock& start_lock,
  30. Lock& lock,
  31. int iterations,
  32. int& counter)
  33. : start_lock_(start_lock),
  34. lock_(lock),
  35. iterations_(iterations),
  36. counter_(counter) {}
  37. void ThreadMain() override {
  38. start_lock_.Acquire();
  39. start_lock_.Release();
  40. for (int i = 0; i < iterations_; i++) {
  41. lock_.Acquire();
  42. ++counter_;
  43. lock_.Release();
  44. }
  45. }
  46. private:
  47. Lock& start_lock_;
  48. Lock& lock_;
  49. const int iterations_;
  50. int& counter_;
  51. };
  52. } // namespace
  53. TEST(PartitionAllocLockTest, Contended) {
  54. int counter = 0; // *Not* atomic.
  55. std::vector<internal::base::PlatformThreadHandle> thread_handles;
  56. constexpr int iterations_per_thread = 1000000;
  57. constexpr int num_threads = 4;
  58. Lock lock;
  59. Lock start_lock;
  60. ThreadDelegateForContended delegate(start_lock, lock, iterations_per_thread,
  61. counter);
  62. start_lock.Acquire(); // Make sure that the threads compete, by waiting until
  63. // all of them have at least been created.
  64. for (int i = 0; i < num_threads; ++i) {
  65. base::PlatformThreadHandle handle;
  66. base::PlatformThreadForTesting::Create(0, &delegate, &handle);
  67. thread_handles.push_back(handle);
  68. }
  69. start_lock.Release();
  70. for (int i = 0; i < num_threads; ++i) {
  71. base::PlatformThreadForTesting::Join(thread_handles[i]);
  72. }
  73. EXPECT_EQ(iterations_per_thread * num_threads, counter);
  74. }
  75. namespace {
  76. class ThreadDelegateForSlowThreads
  77. : public base::PlatformThreadForTesting::Delegate {
  78. public:
  79. explicit ThreadDelegateForSlowThreads(Lock& start_lock,
  80. Lock& lock,
  81. int iterations,
  82. int& counter)
  83. : start_lock_(start_lock),
  84. lock_(lock),
  85. iterations_(iterations),
  86. counter_(counter) {}
  87. void ThreadMain() override {
  88. start_lock_.Acquire();
  89. start_lock_.Release();
  90. for (int i = 0; i < iterations_; i++) {
  91. lock_.Acquire();
  92. ++counter_;
  93. // Hold the lock for a while, to force futex()-based locks to sleep.
  94. base::PlatformThread::Sleep(base::Milliseconds(1));
  95. lock_.Release();
  96. }
  97. }
  98. private:
  99. Lock& start_lock_;
  100. Lock& lock_;
  101. const int iterations_;
  102. int& counter_;
  103. };
  104. } // namespace
  105. TEST(PartitionAllocLockTest, SlowThreads) {
  106. int counter = 0; // *Not* atomic.
  107. std::vector<base::PlatformThreadHandle> thread_handles;
  108. constexpr int iterations_per_thread = 100;
  109. constexpr int num_threads = 4;
  110. Lock lock;
  111. Lock start_lock;
  112. ThreadDelegateForSlowThreads delegate(start_lock, lock, iterations_per_thread,
  113. counter);
  114. start_lock.Acquire(); // Make sure that the threads compete, by waiting until
  115. // all of them have at least been created.
  116. for (int i = 0; i < num_threads; i++) {
  117. base::PlatformThreadHandle handle;
  118. base::PlatformThreadForTesting::Create(0, &delegate, &handle);
  119. thread_handles.push_back(handle);
  120. }
  121. start_lock.Release();
  122. for (int i = 0; i < num_threads; i++) {
  123. base::PlatformThreadForTesting::Join(thread_handles[i]);
  124. }
  125. EXPECT_EQ(iterations_per_thread * num_threads, counter);
  126. }
  127. TEST(PartitionAllocLockTest, AssertAcquired) {
  128. Lock lock;
  129. lock.Acquire();
  130. lock.AssertAcquired();
  131. lock.Release();
  132. }
  133. // AssertAcquired() is only enforced with DCHECK()s.
  134. #if defined(GTEST_HAS_DEATH_TEST) && BUILDFLAG(PA_DCHECK_IS_ON)
  135. TEST(PartitionAllocLockTest, AssertAcquiredDeathTest) {
  136. Lock lock;
  137. EXPECT_DEATH(lock.AssertAcquired(), "");
  138. }
  139. namespace {
  140. class ThreadDelegateForAssertAcquiredAnotherThreadHoldsTheLock
  141. : public base::PlatformThreadForTesting::Delegate {
  142. public:
  143. explicit ThreadDelegateForAssertAcquiredAnotherThreadHoldsTheLock(Lock& lock)
  144. : lock_(lock) {}
  145. void ThreadMain() PA_NO_THREAD_SAFETY_ANALYSIS override { lock_.Acquire(); }
  146. private:
  147. Lock& lock_;
  148. };
  149. } // namespace
  150. TEST(PartitionAllocLockTest, AssertAcquiredAnotherThreadHoldsTheLock) {
  151. Lock lock;
  152. // PA_NO_THREAD_SAFETY_ANALYSIS: The checker rightfully points out that the
  153. // lock is still held at the end of the function, which is what we want here.
  154. ThreadDelegateForAssertAcquiredAnotherThreadHoldsTheLock delegate(lock);
  155. base::PlatformThreadHandle handle;
  156. base::PlatformThreadForTesting::Create(0, &delegate, &handle);
  157. // Join before the test, otherwise some platforms' gtest have trouble with
  158. // EXPECT_DEATH() and multiple live threads.
  159. base::PlatformThreadForTesting::Join(handle);
  160. EXPECT_DEATH(lock.AssertAcquired(), "");
  161. }
  162. #if BUILDFLAG(IS_APPLE)
  163. namespace {
  164. class ThreadDelegateForReinitInOtherThread
  165. : public base::PlatformThreadForTesting::Delegate {
  166. public:
  167. explicit ThreadDelegateForReinitInOtherThread(Lock& lock) : lock_(lock) {}
  168. void ThreadMain() PA_NO_THREAD_SAFETY_ANALYSIS override {
  169. lock_.Reinit();
  170. lock_.Acquire();
  171. lock_.Release();
  172. }
  173. private:
  174. Lock& lock_;
  175. };
  176. } // namespace
  177. // On Apple OSes, it is not allowed to unlock a lock from another thread, so
  178. // we need to re-initialize it.
  179. TEST(PartitionAllocLockTest, ReinitInOtherThread) PA_NO_THREAD_SAFETY_ANALYSIS {
  180. Lock lock;
  181. lock.Acquire();
  182. ThreadDelegateForReinitInOtherThread delegate(lock);
  183. base::PlatformThreadHandle handle;
  184. base::PlatformThreadForTesting::Create(0, &delegate, &handle);
  185. base::PlatformThreadForTesting::Join(handle);
  186. }
  187. #endif // BUILDFLAG(IS_APPLE)
  188. #endif // defined(GTEST_HAS_DEATH_TEST) && BUILDFLAG(PA_DCHECK_IS_ON)
  189. } // namespace partition_alloc::internal