| Index: base/synchronization/read_write_lock_unittest.cc
|
| diff --git a/base/synchronization/read_write_lock_unittest.cc b/base/synchronization/read_write_lock_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bae3ce98ab5b73c6013e0e2e442a3ce0fd1f2aad
|
| --- /dev/null
|
| +++ b/base/synchronization/read_write_lock_unittest.cc
|
| @@ -0,0 +1,223 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/synchronization/read_write_lock.h"
|
| +
|
| +#include <stdlib.h>
|
| +
|
| +#include "base/compiler_specific.h"
|
| +#include "base/macros.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/threading/platform_thread.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +namespace subtle {
|
| +
|
| +// Basic test to make sure that *Acquire()/*Release() don't crash.
|
| +
|
| +class BasicReadWriteLockTestThread : public PlatformThread::Delegate {
|
| + public:
|
| + explicit BasicReadWriteLockTestThread(ReadWriteLock* lock)
|
| + : lock_(lock), acquired_(0) {}
|
| +
|
| + void ThreadMain() override {
|
| + for (int i = 0; i < 10; i++) {
|
| + AutoReadLock locker(*lock_);
|
| + acquired_++;
|
| + }
|
| + for (int i = 0; i < 10; i++) {
|
| + AutoWriteLock locker(*lock_);
|
| + acquired_++;
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
|
| + }
|
| + }
|
| +
|
| + int acquired() const { return acquired_; }
|
| +
|
| + private:
|
| + ReadWriteLock* lock_;
|
| + int acquired_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(BasicReadWriteLockTestThread);
|
| +};
|
| +
|
| +TEST(ReadWriteLockTest, Basic) {
|
| + ReadWriteLock lock;
|
| + BasicReadWriteLockTestThread thread(&lock);
|
| + PlatformThreadHandle handle;
|
| +
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
|
| +
|
| + int acquired = 0;
|
| + for (int i = 0; i < 5; i++) {
|
| + AutoReadLock locker(lock);
|
| + acquired++;
|
| + }
|
| + for (int i = 0; i < 10; i++) {
|
| + AutoWriteLock locker(lock);
|
| + acquired++;
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
|
| + }
|
| + for (int i = 0; i < 5; i++) {
|
| + AutoReadLock locker(lock);
|
| + acquired++;
|
| + }
|
| +
|
| + PlatformThread::Join(handle);
|
| +
|
| + EXPECT_EQ(20, acquired);
|
| + EXPECT_GE(20, thread.acquired());
|
| +}
|
| +
|
| +// Tests that reader locks allow multiple simultaneous reader acquisitions.
|
| +
|
| +class ReaderReadWriteLockTestThread : public PlatformThread::Delegate {
|
| + public:
|
| + ReaderReadWriteLockTestThread(ReadWriteLock* lock) : lock_(lock) {}
|
| +
|
| + void ThreadMain() override {
|
| + AutoReadLock locker(*lock_);
|
| + did_acquire_ = true;
|
| + }
|
| +
|
| + bool did_acquire() const { return did_acquire_; }
|
| +
|
| + private:
|
| + ReadWriteLock* lock_;
|
| + bool did_acquire_ = false;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ReaderReadWriteLockTestThread);
|
| +};
|
| +
|
| +TEST(ReadWriteLockTest, ReaderTwoThreads) {
|
| + ReadWriteLock lock;
|
| +
|
| + AutoReadLock auto_lock(lock);
|
| +
|
| + ReaderReadWriteLockTestThread thread(&lock);
|
| + PlatformThreadHandle handle;
|
| +
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
|
| + PlatformThread::Join(handle);
|
| + EXPECT_TRUE(thread.did_acquire());
|
| +}
|
| +
|
| +// Tests that writer locks exclude reader locks.
|
| +
|
| +class ReadAndWriteReadWriteLockTestThread : public PlatformThread::Delegate {
|
| + public:
|
| + ReadAndWriteReadWriteLockTestThread(ReadWriteLock* lock, int* value)
|
| + : lock_(lock), value_(value),
|
| + event_(true /* manual_reset */, false /* initially_signaled */) {}
|
| +
|
| + void ThreadMain() override {
|
| + AutoWriteLock locker(*lock_);
|
| + (*value_)++;
|
| + event_.Signal();
|
| + }
|
| +
|
| + void Wait() {
|
| + event_.Wait();
|
| + }
|
| +
|
| + private:
|
| + ReadWriteLock* lock_;
|
| + int* value_;
|
| + WaitableEvent event_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ReadAndWriteReadWriteLockTestThread);
|
| +};
|
| +
|
| +TEST(ReadWriteLockTest, ReadAndWriteThreads) {
|
| + ReadWriteLock lock;
|
| + int value = 0;
|
| +
|
| + ReadAndWriteReadWriteLockTestThread thread(&lock, &value);
|
| + PlatformThreadHandle handle;
|
| + {
|
| + AutoReadLock read_locker(lock);
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
|
| +
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
|
| +
|
| + // |value| should be unchanged since we hold a reader lock.
|
| + EXPECT_EQ(0, value);
|
| + }
|
| +
|
| + thread.Wait();
|
| + // After releasing our reader lock, the thread can acquire a write lock and
|
| + // change |value|.
|
| + EXPECT_EQ(1, value);
|
| + PlatformThread::Join(handle);
|
| +}
|
| +
|
| +// Tests that writer locks actually exclude.
|
| +
|
| +class WriterReadWriteLockTestThread : public PlatformThread::Delegate {
|
| + public:
|
| + WriterReadWriteLockTestThread(ReadWriteLock* lock, int* value)
|
| + : lock_(lock), value_(value) {}
|
| +
|
| + // Static helper which can also be called from the main thread.
|
| + static void DoStuff(ReadWriteLock* lock, int* value) {
|
| + for (int i = 0; i < 40; i++) {
|
| + AutoWriteLock locker(*lock);
|
| + int v = *value;
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
|
| + *value = v + 1;
|
| + }
|
| + }
|
| +
|
| + void ThreadMain() override { DoStuff(lock_, value_); }
|
| +
|
| + private:
|
| + ReadWriteLock* lock_;
|
| + int* value_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(WriterReadWriteLockTestThread);
|
| +};
|
| +
|
| +TEST(ReadWriteLockTest, MutexTwoThreads) {
|
| + ReadWriteLock lock;
|
| + int value = 0;
|
| +
|
| + WriterReadWriteLockTestThread thread(&lock, &value);
|
| + PlatformThreadHandle handle;
|
| +
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
|
| +
|
| + WriterReadWriteLockTestThread::DoStuff(&lock, &value);
|
| +
|
| + PlatformThread::Join(handle);
|
| +
|
| + EXPECT_EQ(2 * 40, value);
|
| +}
|
| +
|
| +TEST(ReadWriteLockTest, MutexFourThreads) {
|
| + ReadWriteLock lock;
|
| + int value = 0;
|
| +
|
| + WriterReadWriteLockTestThread thread1(&lock, &value);
|
| + WriterReadWriteLockTestThread thread2(&lock, &value);
|
| + WriterReadWriteLockTestThread thread3(&lock, &value);
|
| + PlatformThreadHandle handle1;
|
| + PlatformThreadHandle handle2;
|
| + PlatformThreadHandle handle3;
|
| +
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
|
| + ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
|
| +
|
| + WriterReadWriteLockTestThread::DoStuff(&lock, &value);
|
| +
|
| + PlatformThread::Join(handle1);
|
| + PlatformThread::Join(handle2);
|
| + PlatformThread::Join(handle3);
|
| +
|
| + EXPECT_EQ(4 * 40, value);
|
| +}
|
| +
|
| +} // namespace subtle
|
| +} // namespace base
|
|
|