1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "mojo/public/utility/mutex.h"
7 #include <stdlib.h> // For |rand()|.
8 #include <time.h> // For |nanosleep()| (defined by POSIX).
12 #include "mojo/public/system/macros.h"
13 #include "mojo/public/utility/thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
19 TEST(MutexTest, TrivialSingleThreaded) {
26 EXPECT_TRUE(mutex.TryLock());
31 MutexLock lock(&mutex);
35 EXPECT_TRUE(mutex.TryLock());
41 enum Type { kTypeLock, kTypeTry };
42 Fiddler(size_t times_to_lock,
47 : times_to_lock_(times_to_lock),
49 should_sleep_(should_sleep),
51 shared_value_(shared_value) {
58 for (size_t i = 0; i < times_to_lock_;) {
62 int old_shared_value = *shared_value_;
65 *shared_value_ = old_shared_value + 1;
71 if (mutex_->TryLock()) {
72 int old_shared_value = *shared_value_;
75 *shared_value_ = old_shared_value + 1;
79 SleepALittle(); // Don't spin.
87 static void SleepALittle() {
88 static const long kNanosPerMilli = 1000000;
89 struct timespec req = {
91 (rand() % 10) * kNanosPerMilli // Nanoseconds.
93 int rv MOJO_ALLOW_UNUSED = nanosleep(&req, NULL);
97 const size_t times_to_lock_;
99 const bool should_sleep_;
101 int* const shared_value_;
103 MOJO_DISALLOW_COPY_AND_ASSIGN(Fiddler);
106 class FiddlerThread : public Thread {
108 // Takes ownership of |fiddler|.
109 FiddlerThread(Fiddler* fiddler)
110 : fiddler_(fiddler) {
113 virtual ~FiddlerThread() {
117 virtual void Run() MOJO_OVERRIDE {
122 Fiddler* const fiddler_;
124 MOJO_DISALLOW_COPY_AND_ASSIGN(FiddlerThread);
127 // This does a stress test (that also checks exclusion).
128 TEST(MutexTest, ThreadedStress) {
129 static const size_t kNumThreads = 20;
130 static const int kTimesToLockEach = 20;
131 assert(kNumThreads % 4 == 0);
134 int shared_value = 0;
136 std::vector<FiddlerThread*> fiddler_threads;
138 for (size_t i = 0; i < kNumThreads; i += 4) {
139 fiddler_threads.push_back(new FiddlerThread(new Fiddler(
140 kTimesToLockEach, Fiddler::kTypeLock, false, &mutex, &shared_value)));
141 fiddler_threads.push_back(new FiddlerThread(new Fiddler(
142 kTimesToLockEach, Fiddler::kTypeTry, false, &mutex, &shared_value)));
143 fiddler_threads.push_back(new FiddlerThread(new Fiddler(
144 kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)));
145 fiddler_threads.push_back(new FiddlerThread(new Fiddler(
146 kTimesToLockEach, Fiddler::kTypeTry, true, &mutex, &shared_value)));
149 for (size_t i = 0; i < kNumThreads; i++)
150 fiddler_threads[i]->Start();
152 // Do some fiddling ourselves.
153 Fiddler(kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)
157 for (size_t i = 0; i < kNumThreads; i++)
158 fiddler_threads[i]->Join();
160 EXPECT_EQ(static_cast<int>(kNumThreads + 1) * kTimesToLockEach, shared_value);
163 for (size_t i = 0; i < kNumThreads; i++)
164 delete fiddler_threads[i];
165 fiddler_threads.clear();
168 class TryThread : public Thread {
170 explicit TryThread(Mutex* mutex) : mutex_(mutex), try_lock_succeeded_() {}
171 virtual ~TryThread() {}
173 virtual void Run() MOJO_OVERRIDE {
174 try_lock_succeeded_ = mutex_->TryLock();
175 if (try_lock_succeeded_)
179 bool try_lock_succeeded() const { return try_lock_succeeded_; }
183 bool try_lock_succeeded_;
185 MOJO_DISALLOW_COPY_AND_ASSIGN(TryThread);
188 TEST(MutexTest, TryLock) {
191 // |TryLock()| should succeed -- we don't have the lock.
193 TryThread thread(&mutex);
196 EXPECT_TRUE(thread.try_lock_succeeded());
200 ASSERT_TRUE(mutex.TryLock());
202 // Now it should fail.
204 TryThread thread(&mutex);
207 EXPECT_FALSE(thread.try_lock_succeeded());
213 // It should succeed again.
215 TryThread thread(&mutex);
218 EXPECT_TRUE(thread.try_lock_succeeded());
223 // Tests of assertions for Debug builds.
225 // Test |AssertHeld()| (which is an actual user API).
226 TEST(MutexTest, DebugAssertHeldFailure) {
228 EXPECT_DEATH(mutex.AssertHeld(), "");
231 // Test other consistency checks.
232 TEST(MutexTest, DebugAssertionFailures) {
233 // Unlock without lock held.
239 // Lock with lock held (on same thread).
246 // Try lock with lock held.
253 // Destroy lock with lock held.
259 #endif // !defined(NDEBUG)