summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-30 05:50:42 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-30 05:50:42 +0000
commit5dd879a6fb6d07222d6a940643301a3e0d5bc010 (patch)
tree37361ad54875a7d2a419591c48ca43a40ced66b4
parent587b40b6124aea9759b6b90ffb01e72fc2610935 (diff)
downloadchromium_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.gyp4
-rw-r--r--base/lock.h4
-rw-r--r--base/lock_unittest.cc213
-rw-r--r--base/platform_thread_unittest.cc104
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);
+ }
+}