123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- // Copyright (c) 2012 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/lock.h"
- #include <stdlib.h>
- #include "base/compiler_specific.h"
- #include "base/debug/activity_tracker.h"
- #include "base/memory/raw_ptr.h"
- #include "base/test/gtest_util.h"
- #include "base/threading/platform_thread.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace base {
- // Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
- class BasicLockTestThread : public PlatformThread::Delegate {
- public:
- explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
- BasicLockTestThread(const BasicLockTestThread&) = delete;
- BasicLockTestThread& operator=(const BasicLockTestThread&) = delete;
- void ThreadMain() override {
- for (int i = 0; i < 10; i++) {
- lock_->Acquire();
- acquired_++;
- lock_->Release();
- }
- for (int i = 0; i < 10; i++) {
- lock_->Acquire();
- acquired_++;
- PlatformThread::Sleep(Milliseconds(rand() % 20));
- lock_->Release();
- }
- for (int i = 0; i < 10; i++) {
- if (lock_->Try()) {
- acquired_++;
- PlatformThread::Sleep(Milliseconds(rand() % 20));
- lock_->Release();
- }
- }
- }
- int acquired() const { return acquired_; }
- private:
- raw_ptr<Lock> lock_;
- int acquired_;
- };
- TEST(LockTest, Basic) {
- Lock lock;
- BasicLockTestThread thread(&lock);
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- int acquired = 0;
- for (int i = 0; i < 5; i++) {
- lock.Acquire();
- acquired++;
- lock.Release();
- }
- for (int i = 0; i < 10; i++) {
- lock.Acquire();
- acquired++;
- PlatformThread::Sleep(Milliseconds(rand() % 20));
- lock.Release();
- }
- for (int i = 0; i < 10; i++) {
- if (lock.Try()) {
- acquired++;
- PlatformThread::Sleep(Milliseconds(rand() % 20));
- lock.Release();
- }
- }
- for (int i = 0; i < 5; i++) {
- lock.Acquire();
- acquired++;
- PlatformThread::Sleep(Milliseconds(rand() % 20));
- lock.Release();
- }
- PlatformThread::Join(handle);
- EXPECT_GE(acquired, 20);
- EXPECT_GE(thread.acquired(), 20);
- }
- // Test that Try() works as expected -------------------------------------------
- class TryLockTestThread : public PlatformThread::Delegate {
- public:
- explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
- TryLockTestThread(const TryLockTestThread&) = delete;
- TryLockTestThread& operator=(const TryLockTestThread&) = delete;
- void ThreadMain() override {
- // The local variable is required for the static analyzer to see that the
- // lock is properly released.
- bool got_lock = lock_->Try();
- got_lock_ = got_lock;
- if (got_lock)
- lock_->Release();
- }
- bool got_lock() const { return got_lock_; }
- private:
- raw_ptr<Lock> lock_;
- bool got_lock_;
- };
- TEST(LockTest, TryLock) {
- Lock lock;
- ASSERT_TRUE(lock.Try());
- lock.AssertAcquired();
- // This thread will not be able to get the lock.
- {
- TryLockTestThread thread(&lock);
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Join(handle);
- ASSERT_FALSE(thread.got_lock());
- }
- lock.Release();
- // This thread will....
- {
- TryLockTestThread thread(&lock);
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Join(handle);
- ASSERT_TRUE(thread.got_lock());
- // But it released it....
- ASSERT_TRUE(lock.Try());
- lock.AssertAcquired();
- }
- lock.Release();
- }
- TEST(LockTest, TryTrackedLock) {
- // Enable the activity tracker.
- debug::GlobalActivityTracker::CreateWithLocalMemory(64 << 10, 0, "", 3, 0);
- Lock lock;
- ASSERT_TRUE(lock.Try());
- lock.AssertAcquired();
- // This thread will not be able to get the lock.
- {
- TryLockTestThread thread(&lock);
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Join(handle);
- ASSERT_FALSE(thread.got_lock());
- }
- lock.Release();
- // This thread will....
- {
- TryLockTestThread thread(&lock);
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- PlatformThread::Join(handle);
- ASSERT_TRUE(thread.got_lock());
- // But it released it....
- ASSERT_TRUE(lock.Try());
- lock.AssertAcquired();
- }
- lock.Release();
- debug::GlobalActivityTracker::ReleaseForTesting();
- }
- // Tests that locks actually exclude -------------------------------------------
- class MutexLockTestThread : public PlatformThread::Delegate {
- public:
- MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
- MutexLockTestThread(const MutexLockTestThread&) = delete;
- MutexLockTestThread& operator=(const MutexLockTestThread&) = delete;
- // Static helper which can also be called from the main thread.
- static void DoStuff(Lock* lock, int* value) {
- for (int i = 0; i < 40; i++) {
- lock->Acquire();
- int v = *value;
- PlatformThread::Sleep(Milliseconds(rand() % 10));
- *value = v + 1;
- lock->Release();
- }
- }
- void ThreadMain() override { DoStuff(lock_, value_); }
- private:
- raw_ptr<Lock> lock_;
- raw_ptr<int> value_;
- };
- TEST(LockTest, MutexTwoThreads) {
- Lock lock;
- int value = 0;
- MutexLockTestThread thread(&lock, &value);
- PlatformThreadHandle handle;
- ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
- MutexLockTestThread::DoStuff(&lock, &value);
- PlatformThread::Join(handle);
- EXPECT_EQ(2 * 40, value);
- }
- TEST(LockTest, MutexFourThreads) {
- Lock lock;
- int value = 0;
- MutexLockTestThread thread1(&lock, &value);
- MutexLockTestThread thread2(&lock, &value);
- MutexLockTestThread 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));
- MutexLockTestThread::DoStuff(&lock, &value);
- PlatformThread::Join(handle1);
- PlatformThread::Join(handle2);
- PlatformThread::Join(handle3);
- EXPECT_EQ(4 * 40, value);
- }
- TEST(LockTest, AutoLockMaybe) {
- Lock lock;
- {
- AutoLockMaybe auto_lock(&lock);
- lock.AssertAcquired();
- }
- EXPECT_DCHECK_DEATH(lock.AssertAcquired());
- }
- TEST(LockTest, AutoLockMaybeNull) {
- AutoLockMaybe auto_lock(nullptr);
- }
- TEST(LockTest, ReleasableAutoLockExplicitRelease) {
- Lock lock;
- ReleasableAutoLock auto_lock(&lock);
- lock.AssertAcquired();
- auto_lock.Release();
- EXPECT_DCHECK_DEATH(lock.AssertAcquired());
- }
- TEST(LockTest, ReleasableAutoLockImplicitRelease) {
- Lock lock;
- {
- ReleasableAutoLock auto_lock(&lock);
- lock.AssertAcquired();
- }
- EXPECT_DCHECK_DEATH(lock.AssertAcquired());
- }
- } // namespace base
|