summaryrefslogtreecommitdiffstats
path: root/rlz
diff options
context:
space:
mode:
authorivankr@chromium.org <ivankr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-06 10:38:59 +0000
committerivankr@chromium.org <ivankr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-06 10:38:59 +0000
commitafb14c2cc6095d515aa0754fb6e1e1c44db091b6 (patch)
treef22113e474f2b7329e3f49b8ff887104f0a29775 /rlz
parentbfdd5c40a2e31b52cda6b1bb782eadb286f6f2d5 (diff)
downloadchromium_src-afb14c2cc6095d515aa0754fb6e1e1c44db091b6.zip
chromium_src-afb14c2cc6095d515aa0754fb6e1e1c44db091b6.tar.gz
chromium_src-afb14c2cc6095d515aa0754fb6e1e1c44db091b6.tar.bz2
[cros] Add RecursiveLock for CrOS implementation.
BUG=157348 Review URL: https://chromiumcodereview.appspot.com/11361057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166186 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'rlz')
-rw-r--r--rlz/lib/recursive_lock.cc40
-rw-r--r--rlz/lib/recursive_lock.h34
-rw-r--r--rlz/lib/recursive_lock_unittest.cc234
-rw-r--r--rlz/rlz.gyp14
4 files changed, 322 insertions, 0 deletions
diff --git a/rlz/lib/recursive_lock.cc b/rlz/lib/recursive_lock.cc
new file mode 100644
index 0000000..686cf0e
--- /dev/null
+++ b/rlz/lib/recursive_lock.cc
@@ -0,0 +1,40 @@
+// 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 "rlz/lib/recursive_lock.h"
+
+#include "base/logging.h"
+
+namespace rlz_lib {
+
+RecursiveLock::RecursiveLock()
+ : owner_(),
+ recursion_() {
+}
+
+RecursiveLock::~RecursiveLock() {
+}
+
+void RecursiveLock::Acquire() {
+ base::subtle::Atomic32 me = base::PlatformThread::CurrentId();
+ if (me != base::subtle::NoBarrier_Load(&owner_)) {
+ lock_.Acquire();
+ DCHECK(!recursion_);
+ DCHECK(!owner_);
+ base::subtle::NoBarrier_Store(&owner_, me);
+ }
+ ++recursion_;
+}
+
+void RecursiveLock::Release() {
+ DCHECK_EQ(base::subtle::NoBarrier_Load(&owner_),
+ base::PlatformThread::CurrentId());
+ DCHECK_GT(recursion_, 0);
+ if (!--recursion_) {
+ base::subtle::NoBarrier_Store(&owner_, 0);
+ lock_.Release();
+ }
+}
+
+} // namespace rlz_lib
diff --git a/rlz/lib/recursive_lock.h b/rlz/lib/recursive_lock.h
new file mode 100644
index 0000000..43c95747
--- /dev/null
+++ b/rlz/lib/recursive_lock.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
+#define RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+
+namespace rlz_lib {
+
+
+class RecursiveLock {
+ public:
+ RecursiveLock();
+ ~RecursiveLock();
+
+ void Acquire();
+ void Release();
+
+ private:
+ // Underlying non-recursive lock.
+ base::Lock lock_;
+ // Owner thread ID.
+ base::subtle::Atomic32 owner_;
+ // Recursion lock depth.
+ int recursion_;
+};
+
+} // namespace rlz_lib
+
+#endif // RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
diff --git a/rlz/lib/recursive_lock_unittest.cc b/rlz/lib/recursive_lock_unittest.cc
new file mode 100644
index 0000000..916af7f
--- /dev/null
+++ b/rlz/lib/recursive_lock_unittest.cc
@@ -0,0 +1,234 @@
+// 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 "rlz/lib/recursive_lock.h"
+
+#include <stdlib.h>
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::kNullThreadHandle;
+using base::PlatformThread;
+using base::PlatformThreadHandle;
+using base::TimeDelta;
+
+namespace rlz_lib {
+
+// Basic test to make sure that Acquire()/Release() don't crash.
+class BasicLockTestThread : public PlatformThread::Delegate {
+ public:
+ BasicLockTestThread(RecursiveLock* 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();
+ }
+ }
+
+ int acquired() const { return acquired_; }
+
+ private:
+ RecursiveLock* lock_;
+ int acquired_;
+
+ DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
+};
+
+TEST(RecursiveLockTest, Basic) {
+ RecursiveLock 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(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_EQ(acquired, 20);
+ EXPECT_EQ(thread.acquired(), 20);
+}
+
+// Tests that locks are actually exclusive.
+class MutexLockTestThread : public PlatformThread::Delegate {
+ public:
+ MutexLockTestThread(RecursiveLock* lock, int* value)
+ : lock_(lock),
+ value_(value) {
+ }
+
+ // Static helper which can also be called from the main thread.
+ static void DoStuff(RecursiveLock* 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:
+ RecursiveLock* lock_;
+ int* value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
+};
+
+TEST(RecursiveLockTest, MutexTwoThreads) {
+ RecursiveLock 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(RecursiveLockTest, MutexFourThreads) {
+ RecursiveLock 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);
+}
+
+// Tests that locks are recursive.
+class MutexRecursiveLockTestThread : public PlatformThread::Delegate {
+ public:
+ MutexRecursiveLockTestThread(RecursiveLock* lock, int* value)
+ : lock_(lock),
+ value_(value) {
+ }
+
+ // Static helper which can also be called from the main thread.
+ static void DoStuff(RecursiveLock* lock, int* value) {
+ for (int i = 0; i < 20; i++) {
+ // First lock.
+ lock->Acquire();
+ int v = *value;
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
+ *value = v + 1;
+ {
+ // Recursive lock.
+ lock->Acquire();
+ int v = *value;
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
+ *value = v + 1;
+ lock->Release();
+ }
+ v = *value;
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
+ *value = v + 1;
+ lock->Release();
+ }
+ }
+
+ virtual void ThreadMain() OVERRIDE {
+ DoStuff(lock_, value_);
+ }
+
+ private:
+ RecursiveLock* lock_;
+ int* value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MutexRecursiveLockTestThread);
+};
+
+
+TEST(RecursiveLockTest, MutexTwoThreadsRecursive) {
+ RecursiveLock lock;
+ int value = 0;
+
+ MutexRecursiveLockTestThread thread(&lock, &value);
+ PlatformThreadHandle handle = kNullThreadHandle;
+
+ ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+ MutexRecursiveLockTestThread::DoStuff(&lock, &value);
+
+ PlatformThread::Join(handle);
+
+ EXPECT_EQ(2 * 60, value);
+}
+
+TEST(RecursiveLockTest, MutexFourThreadsRecursive) {
+ RecursiveLock lock;
+ int value = 0;
+
+ MutexRecursiveLockTestThread thread1(&lock, &value);
+ MutexRecursiveLockTestThread thread2(&lock, &value);
+ MutexRecursiveLockTestThread 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));
+
+ MutexRecursiveLockTestThread::DoStuff(&lock, &value);
+
+ PlatformThread::Join(handle1);
+ PlatformThread::Join(handle2);
+ PlatformThread::Join(handle3);
+
+ EXPECT_EQ(4 * 60, value);
+}
+
+} // namespace rlz_lib
diff --git a/rlz/rlz.gyp b/rlz/rlz.gyp
index 123eaa0..cdd66dc 100644
--- a/rlz/rlz.gyp
+++ b/rlz/rlz.gyp
@@ -42,6 +42,8 @@
'lib/lib_values.cc',
'lib/machine_id.cc',
'lib/machine_id.h',
+ 'lib/recursive_lock.cc',
+ 'lib/recursive_lock.h',
'lib/rlz_enums.h',
'lib/rlz_lib.cc',
'lib/rlz_lib.h',
@@ -92,6 +94,12 @@
],
},
}],
+ ['chromeos==0', {
+ 'sources!': [
+ 'lib/recursive_lock.cc',
+ 'lib/recursive_lock.h',
+ ]
+ }],
],
},
{
@@ -110,6 +118,7 @@
'lib/financial_ping_test.cc',
'lib/lib_values_unittest.cc',
'lib/machine_id_unittest.cc',
+ 'lib/recursive_lock_unittest.cc',
'lib/rlz_lib_test.cc',
'lib/string_utils_unittest.cc',
'test/rlz_test_helpers.cc',
@@ -122,6 +131,11 @@
'dependencies': [
'../net/net.gyp:net_test_support',
],
+ }],
+ ['chromeos==0', {
+ 'sources!': [
+ 'lib/recursive_lock_unittest.cc',
+ ],
}]
],
},