diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-30 05:50:42 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-30 05:50:42 +0000 |
commit | 5dd879a6fb6d07222d6a940643301a3e0d5bc010 (patch) | |
tree | 37361ad54875a7d2a419591c48ca43a40ced66b4 | |
parent | 587b40b6124aea9759b6b90ffb01e72fc2610935 (diff) | |
download | chromium_src-5dd879a6fb6d07222d6a940643301a3e0d5bc010.zip chromium_src-5dd879a6fb6d07222d6a940643301a3e0d5bc010.tar.gz chromium_src-5dd879a6fb6d07222d6a940643301a3e0d5bc010.tar.bz2 |
Add unit tests for base/platform_thread.* and base/lock.*.
BUG=none
TEST=base_unittests
Review URL: http://codereview.chromium.org/3030025
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54283 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/base.gyp | 4 | ||||
-rw-r--r-- | base/lock.h | 4 | ||||
-rw-r--r-- | base/lock_unittest.cc | 213 | ||||
-rw-r--r-- | base/platform_thread_unittest.cc | 104 |
4 files changed, 323 insertions, 2 deletions
diff --git a/base/base.gyp b/base/base.gyp index d2c9a68..d53bd13 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -76,7 +76,7 @@ 'data_pack_unittest.cc', 'debug_util_unittest.cc', 'dir_reader_posix_unittest.cc', - 'env_var_unittest.cc', + 'env_var_unittest.cc', 'event_trace_consumer_win_unittest.cc', 'event_trace_controller_win_unittest.cc', 'event_trace_provider_win_unittest.cc', @@ -100,6 +100,7 @@ 'leak_tracker_unittest.cc', 'linked_list_unittest.cc', 'linked_ptr_unittest.cc', + 'lock_unittest.cc', 'mac_util_unittest.mm', 'message_loop_proxy_impl_unittest.cc', 'message_loop_unittest.cc', @@ -109,6 +110,7 @@ 'path_service_unittest.cc', 'pe_image_unittest.cc', 'pickle_unittest.cc', + 'platform_thread_unittest.cc', 'pr_time_unittest.cc', 'process_util_unittest.cc', 'process_util_unittest_mac.h', diff --git a/base/lock.h b/base/lock.h index a9b2f88..0ae4861 100644 --- a/base/lock.h +++ b/base/lock.h @@ -21,7 +21,9 @@ class Lock { void Release() { lock_.Unlock(); } // If the lock is not held, take it and return true. If the lock is already - // held by another thread, immediately return false. + // held by another thread, immediately return false. This must not be called + // by a thread already holding the lock (what happens is undefined and an + // assertion may fail). bool Try() { return lock_.Try(); } // Null implementation if not debug. diff --git a/base/lock_unittest.cc b/base/lock_unittest.cc new file mode 100644 index 0000000..cf99df9 --- /dev/null +++ b/base/lock_unittest.cc @@ -0,0 +1,213 @@ +// Copyright (c) 2010 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/lock.h" + +#include <stdlib.h> + +#include "base/platform_thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +typedef testing::Test LockTest; + +// Basic test to make sure that Acquire()/Release()/Try() don't crash ---------- + +class BasicLockTestThread : public PlatformThread::Delegate { + public: + BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {} + + virtual void ThreadMain() { + for (int i = 0; i < 10; i++) { + lock_->Acquire(); + acquired_++; + lock_->Release(); + } + for (int i = 0; i < 10; i++) { + lock_->Acquire(); + acquired_++; + PlatformThread::Sleep(rand() % 20); + lock_->Release(); + } + for (int i = 0; i < 10; i++) { + if (lock_->Try()) { + acquired_++; + PlatformThread::Sleep(rand() % 20); + lock_->Release(); + } + } + } + + int acquired() const { return acquired_; } + + private: + Lock* lock_; + int acquired_; + + DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); +}; + +TEST_F(LockTest, Basic) { + Lock lock; + BasicLockTestThread thread(&lock); + PlatformThreadHandle handle = kNullThreadHandle; + + 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(rand() % 20); + lock.Release(); + } + for (int i = 0; i < 10; i++) { + if (lock.Try()) { + acquired++; + PlatformThread::Sleep(rand() % 20); + lock.Release(); + } + } + for (int i = 0; i < 5; i++) { + lock.Acquire(); + acquired++; + PlatformThread::Sleep(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: + TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {} + + virtual void ThreadMain() { + 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_F(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 = kNullThreadHandle; + + 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 = kNullThreadHandle; + + 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(rand() % 10); + *value = v + 1; + lock->Release(); + } + } + + virtual void ThreadMain() { + DoStuff(lock_, value_); + } + + private: + Lock* lock_; + int* value_; + + DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread); +}; + +TEST_F(LockTest, MutexTwoThreads) { + Lock lock; + int value = 0; + + MutexLockTestThread thread(&lock, &value); + PlatformThreadHandle handle = kNullThreadHandle; + + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); + + MutexLockTestThread::DoStuff(&lock, &value); + + PlatformThread::Join(handle); + + EXPECT_EQ(2 * 40, value); +} + +TEST_F(LockTest, MutexFourThreads) { + Lock lock; + int value = 0; + + MutexLockTestThread thread1(&lock, &value); + MutexLockTestThread thread2(&lock, &value); + MutexLockTestThread thread3(&lock, &value); + PlatformThreadHandle handle1 = kNullThreadHandle; + PlatformThreadHandle handle2 = kNullThreadHandle; + PlatformThreadHandle handle3 = kNullThreadHandle; + + 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); +} diff --git a/base/platform_thread_unittest.cc b/base/platform_thread_unittest.cc new file mode 100644 index 0000000..67dce15 --- /dev/null +++ b/base/platform_thread_unittest.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2010 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/platform_thread.h" + +#include "testing/gtest/include/gtest/gtest.h" + +typedef testing::Test PlatformThreadTest; + +// Trivial tests that thread runs and doesn't crash on create and join --------- + +class TrivialThread : public PlatformThread::Delegate { + public: + TrivialThread() : did_run_(false) {} + + virtual void ThreadMain() { + did_run_ = true; + } + + bool did_run() const { return did_run_; } + + private: + bool did_run_; + + DISALLOW_COPY_AND_ASSIGN(TrivialThread); +}; + +TEST_F(PlatformThreadTest, Trivial) { + TrivialThread thread; + PlatformThreadHandle handle = kNullThreadHandle; + + ASSERT_FALSE(thread.did_run()); + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); + PlatformThread::Join(handle); + ASSERT_TRUE(thread.did_run()); +} + +TEST_F(PlatformThreadTest, TrivialTimesTen) { + TrivialThread thread[10]; + PlatformThreadHandle handle[arraysize(thread)]; + + for (size_t n = 0; n < arraysize(thread); n++) + ASSERT_FALSE(thread[n].did_run()); + for (size_t n = 0; n < arraysize(thread); n++) + ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); + for (size_t n = 0; n < arraysize(thread); n++) + PlatformThread::Join(handle[n]); + for (size_t n = 0; n < arraysize(thread); n++) + ASSERT_TRUE(thread[n].did_run()); +} + +// Tests of basic thread functions --------------------------------------------- + +class FunctionTestThread : public TrivialThread { + public: + FunctionTestThread() {} + + virtual void ThreadMain() { + thread_id_ = PlatformThread::CurrentId(); + PlatformThread::YieldCurrentThread(); + PlatformThread::Sleep(50); + + TrivialThread::ThreadMain(); + } + + PlatformThreadId thread_id() const { return thread_id_; } + + private: + PlatformThreadId thread_id_; + + DISALLOW_COPY_AND_ASSIGN(FunctionTestThread); +}; + +TEST_F(PlatformThreadTest, Function) { + PlatformThreadId main_thread_id = PlatformThread::CurrentId(); + + FunctionTestThread thread; + PlatformThreadHandle handle = kNullThreadHandle; + + ASSERT_FALSE(thread.did_run()); + ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle)); + PlatformThread::Join(handle); + ASSERT_TRUE(thread.did_run()); + EXPECT_NE(thread.thread_id(), main_thread_id); +} + +TEST_F(PlatformThreadTest, FunctionTimesTen) { + PlatformThreadId main_thread_id = PlatformThread::CurrentId(); + + FunctionTestThread thread[10]; + PlatformThreadHandle handle[arraysize(thread)]; + + for (size_t n = 0; n < arraysize(thread); n++) + ASSERT_FALSE(thread[n].did_run()); + for (size_t n = 0; n < arraysize(thread); n++) + ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n])); + for (size_t n = 0; n < arraysize(thread); n++) + PlatformThread::Join(handle[n]); + for (size_t n = 0; n < arraysize(thread); n++) { + ASSERT_TRUE(thread[n].did_run()); + EXPECT_NE(thread[n].thread_id(), main_thread_id); + } +} |