OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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/read_write_lock.h" |
| 6 |
| 7 #include <stdlib.h> |
| 8 |
| 9 #include "base/compiler_specific.h" |
| 10 #include "base/macros.h" |
| 11 #include "base/synchronization/waitable_event.h" |
| 12 #include "base/threading/platform_thread.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" |
| 14 |
| 15 namespace base { |
| 16 namespace subtle { |
| 17 |
| 18 // Basic test to make sure that *Acquire()/*Release() don't crash. |
| 19 |
| 20 class BasicReadWriteLockTestThread : public PlatformThread::Delegate { |
| 21 public: |
| 22 explicit BasicReadWriteLockTestThread(ReadWriteLock* lock) |
| 23 : lock_(lock), acquired_(0) {} |
| 24 |
| 25 void ThreadMain() override { |
| 26 for (int i = 0; i < 10; i++) { |
| 27 AutoReadLock locker(*lock_); |
| 28 acquired_++; |
| 29 } |
| 30 for (int i = 0; i < 10; i++) { |
| 31 AutoWriteLock locker(*lock_); |
| 32 acquired_++; |
| 33 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); |
| 34 } |
| 35 } |
| 36 |
| 37 int acquired() const { return acquired_; } |
| 38 |
| 39 private: |
| 40 ReadWriteLock* lock_; |
| 41 int acquired_; |
| 42 |
| 43 DISALLOW_COPY_AND_ASSIGN(BasicReadWriteLockTestThread); |
| 44 }; |
| 45 |
| 46 TEST(ReadWriteLockTest, Basic) { |
| 47 ReadWriteLock lock; |
| 48 BasicReadWriteLockTestThread thread(&lock); |
| 49 PlatformThreadHandle handle; |
| 50 |
| 51 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 52 |
| 53 int acquired = 0; |
| 54 for (int i = 0; i < 5; i++) { |
| 55 AutoReadLock locker(lock); |
| 56 acquired++; |
| 57 } |
| 58 for (int i = 0; i < 10; i++) { |
| 59 AutoWriteLock locker(lock); |
| 60 acquired++; |
| 61 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20)); |
| 62 } |
| 63 for (int i = 0; i < 5; i++) { |
| 64 AutoReadLock locker(lock); |
| 65 acquired++; |
| 66 } |
| 67 |
| 68 PlatformThread::Join(handle); |
| 69 |
| 70 EXPECT_EQ(20, acquired); |
| 71 EXPECT_GE(20, thread.acquired()); |
| 72 } |
| 73 |
| 74 // Tests that reader locks allow multiple simultaneous reader acquisitions. |
| 75 |
| 76 class ReaderReadWriteLockTestThread : public PlatformThread::Delegate { |
| 77 public: |
| 78 ReaderReadWriteLockTestThread(ReadWriteLock* lock) : lock_(lock) {} |
| 79 |
| 80 void ThreadMain() override { |
| 81 AutoReadLock locker(*lock_); |
| 82 did_acquire_ = true; |
| 83 } |
| 84 |
| 85 bool did_acquire() const { return did_acquire_; } |
| 86 |
| 87 private: |
| 88 ReadWriteLock* lock_; |
| 89 bool did_acquire_ = false; |
| 90 |
| 91 DISALLOW_COPY_AND_ASSIGN(ReaderReadWriteLockTestThread); |
| 92 }; |
| 93 |
| 94 TEST(ReadWriteLockTest, ReaderTwoThreads) { |
| 95 ReadWriteLock lock; |
| 96 |
| 97 AutoReadLock auto_lock(lock); |
| 98 |
| 99 ReaderReadWriteLockTestThread thread(&lock); |
| 100 PlatformThreadHandle handle; |
| 101 |
| 102 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 103 PlatformThread::Join(handle); |
| 104 EXPECT_TRUE(thread.did_acquire()); |
| 105 } |
| 106 |
| 107 // Tests that writer locks exclude reader locks. |
| 108 |
| 109 class ReadAndWriteReadWriteLockTestThread : public PlatformThread::Delegate { |
| 110 public: |
| 111 ReadAndWriteReadWriteLockTestThread(ReadWriteLock* lock, int* value) |
| 112 : lock_(lock), value_(value), |
| 113 event_(true /* manual_reset */, false /* initially_signaled */) {} |
| 114 |
| 115 void ThreadMain() override { |
| 116 AutoWriteLock locker(*lock_); |
| 117 (*value_)++; |
| 118 event_.Signal(); |
| 119 } |
| 120 |
| 121 void Wait() { |
| 122 event_.Wait(); |
| 123 } |
| 124 |
| 125 private: |
| 126 ReadWriteLock* lock_; |
| 127 int* value_; |
| 128 WaitableEvent event_; |
| 129 |
| 130 DISALLOW_COPY_AND_ASSIGN(ReadAndWriteReadWriteLockTestThread); |
| 131 }; |
| 132 |
| 133 TEST(ReadWriteLockTest, ReadAndWriteThreads) { |
| 134 ReadWriteLock lock; |
| 135 int value = 0; |
| 136 |
| 137 ReadAndWriteReadWriteLockTestThread thread(&lock, &value); |
| 138 PlatformThreadHandle handle; |
| 139 { |
| 140 AutoReadLock read_locker(lock); |
| 141 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 142 |
| 143 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); |
| 144 |
| 145 // |value| should be unchanged since we hold a reader lock. |
| 146 EXPECT_EQ(0, value); |
| 147 } |
| 148 |
| 149 thread.Wait(); |
| 150 // After releasing our reader lock, the thread can acquire a write lock and |
| 151 // change |value|. |
| 152 EXPECT_EQ(1, value); |
| 153 PlatformThread::Join(handle); |
| 154 } |
| 155 |
| 156 // Tests that writer locks actually exclude. |
| 157 |
| 158 class WriterReadWriteLockTestThread : public PlatformThread::Delegate { |
| 159 public: |
| 160 WriterReadWriteLockTestThread(ReadWriteLock* lock, int* value) |
| 161 : lock_(lock), value_(value) {} |
| 162 |
| 163 // Static helper which can also be called from the main thread. |
| 164 static void DoStuff(ReadWriteLock* lock, int* value) { |
| 165 for (int i = 0; i < 40; i++) { |
| 166 AutoWriteLock locker(*lock); |
| 167 int v = *value; |
| 168 PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10)); |
| 169 *value = v + 1; |
| 170 } |
| 171 } |
| 172 |
| 173 void ThreadMain() override { DoStuff(lock_, value_); } |
| 174 |
| 175 private: |
| 176 ReadWriteLock* lock_; |
| 177 int* value_; |
| 178 |
| 179 DISALLOW_COPY_AND_ASSIGN(WriterReadWriteLockTestThread); |
| 180 }; |
| 181 |
| 182 TEST(ReadWriteLockTest, MutexTwoThreads) { |
| 183 ReadWriteLock lock; |
| 184 int value = 0; |
| 185 |
| 186 WriterReadWriteLockTestThread thread(&lock, &value); |
| 187 PlatformThreadHandle handle; |
| 188 |
| 189 ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); |
| 190 |
| 191 WriterReadWriteLockTestThread::DoStuff(&lock, &value); |
| 192 |
| 193 PlatformThread::Join(handle); |
| 194 |
| 195 EXPECT_EQ(2 * 40, value); |
| 196 } |
| 197 |
| 198 TEST(ReadWriteLockTest, MutexFourThreads) { |
| 199 ReadWriteLock lock; |
| 200 int value = 0; |
| 201 |
| 202 WriterReadWriteLockTestThread thread1(&lock, &value); |
| 203 WriterReadWriteLockTestThread thread2(&lock, &value); |
| 204 WriterReadWriteLockTestThread thread3(&lock, &value); |
| 205 PlatformThreadHandle handle1; |
| 206 PlatformThreadHandle handle2; |
| 207 PlatformThreadHandle handle3; |
| 208 |
| 209 ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1)); |
| 210 ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2)); |
| 211 ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3)); |
| 212 |
| 213 WriterReadWriteLockTestThread::DoStuff(&lock, &value); |
| 214 |
| 215 PlatformThread::Join(handle1); |
| 216 PlatformThread::Join(handle2); |
| 217 PlatformThread::Join(handle3); |
| 218 |
| 219 EXPECT_EQ(4 * 40, value); |
| 220 } |
| 221 |
| 222 } // namespace subtle |
| 223 } // namespace base |
OLD | NEW |