chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
// 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 "butil/synchronization/lock.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "butil/compiler_specific.h"
|
||||
#include "butil/threading/platform_thread.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace butil {
|
||||
|
||||
// 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) {}
|
||||
|
||||
virtual 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(TimeDelta::FromMilliseconds(rand() % 20));
|
||||
lock_->Release();
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (lock_->Try()) {
|
||||
acquired_++;
|
||||
PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
|
||||
lock_->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int acquired() const { return acquired_; }
|
||||
|
||||
private:
|
||||
Lock* lock_;
|
||||
int acquired_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
|
||||
};
|
||||
|
||||
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(TimeDelta::FromMilliseconds(rand() % 20));
|
||||
lock.Release();
|
||||
}
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (lock.Try()) {
|
||||
acquired++;
|
||||
PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
|
||||
lock.Release();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
lock.Acquire();
|
||||
acquired++;
|
||||
PlatformThread::Sleep(TimeDelta::FromMilliseconds(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) {}
|
||||
|
||||
virtual void ThreadMain() OVERRIDE {
|
||||
got_lock_ = lock_->Try();
|
||||
if (got_lock_)
|
||||
lock_->Release();
|
||||
}
|
||||
|
||||
bool got_lock() const { return got_lock_; }
|
||||
|
||||
private:
|
||||
Lock* lock_;
|
||||
bool got_lock_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
|
||||
};
|
||||
|
||||
TEST(LockTest, TryLock) {
|
||||
Lock lock;
|
||||
|
||||
ASSERT_TRUE(lock.Try());
|
||||
// We now have the lock....
|
||||
|
||||
// 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.Release();
|
||||
}
|
||||
|
||||
// Tests that locks actually exclude -------------------------------------------
|
||||
|
||||
class MutexLockTestThread : public PlatformThread::Delegate {
|
||||
public:
|
||||
MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
|
||||
|
||||
// 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(TimeDelta::FromMilliseconds(rand() % 10));
|
||||
*value = v + 1;
|
||||
lock->Release();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ThreadMain() OVERRIDE {
|
||||
DoStuff(lock_, value_);
|
||||
}
|
||||
|
||||
private:
|
||||
Lock* lock_;
|
||||
int* value_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace butil
|
||||
Reference in New Issue
Block a user