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/cpp/utility/mutex.h"
7 #include <stdlib.h> // For |rand()|.
8 #include <time.h> // For |nanosleep()| (defined by POSIX).
12 #include "mojo/public/cpp/system/macros.h"
13 #include "mojo/public/cpp/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
= nanosleep(&req
, NULL
);
94 MOJO_ALLOW_UNUSED_LOCAL(rv
);
98 const size_t times_to_lock_
;
100 const bool should_sleep_
;
102 int* const shared_value_
;
104 MOJO_DISALLOW_COPY_AND_ASSIGN(Fiddler
);
107 class FiddlerThread
: public Thread
{
109 // Takes ownership of |fiddler|.
110 FiddlerThread(Fiddler
* fiddler
)
111 : fiddler_(fiddler
) {
114 ~FiddlerThread() override
{ delete fiddler_
; }
116 void Run() override
{ fiddler_
->Fiddle(); }
119 Fiddler
* const fiddler_
;
121 MOJO_DISALLOW_COPY_AND_ASSIGN(FiddlerThread
);
124 // This does a stress test (that also checks exclusion).
125 TEST(MutexTest
, ThreadedStress
) {
126 static const size_t kNumThreads
= 20;
127 static const int kTimesToLockEach
= 20;
128 assert(kNumThreads
% 4 == 0);
131 int shared_value
= 0;
133 std::vector
<FiddlerThread
*> fiddler_threads
;
135 for (size_t i
= 0; i
< kNumThreads
; i
+= 4) {
136 fiddler_threads
.push_back(new FiddlerThread(new Fiddler(
137 kTimesToLockEach
, Fiddler::kTypeLock
, false, &mutex
, &shared_value
)));
138 fiddler_threads
.push_back(new FiddlerThread(new Fiddler(
139 kTimesToLockEach
, Fiddler::kTypeTry
, false, &mutex
, &shared_value
)));
140 fiddler_threads
.push_back(new FiddlerThread(new Fiddler(
141 kTimesToLockEach
, Fiddler::kTypeLock
, true, &mutex
, &shared_value
)));
142 fiddler_threads
.push_back(new FiddlerThread(new Fiddler(
143 kTimesToLockEach
, Fiddler::kTypeTry
, true, &mutex
, &shared_value
)));
146 for (size_t i
= 0; i
< kNumThreads
; i
++)
147 fiddler_threads
[i
]->Start();
149 // Do some fiddling ourselves.
150 Fiddler(kTimesToLockEach
, Fiddler::kTypeLock
, true, &mutex
, &shared_value
)
154 for (size_t i
= 0; i
< kNumThreads
; i
++)
155 fiddler_threads
[i
]->Join();
157 EXPECT_EQ(static_cast<int>(kNumThreads
+ 1) * kTimesToLockEach
, shared_value
);
160 for (size_t i
= 0; i
< kNumThreads
; i
++)
161 delete fiddler_threads
[i
];
162 fiddler_threads
.clear();
165 class TryThread
: public Thread
{
167 explicit TryThread(Mutex
* mutex
) : mutex_(mutex
), try_lock_succeeded_() {}
168 ~TryThread() override
{}
170 void Run() override
{
171 try_lock_succeeded_
= mutex_
->TryLock();
172 if (try_lock_succeeded_
)
176 bool try_lock_succeeded() const { return try_lock_succeeded_
; }
180 bool try_lock_succeeded_
;
182 MOJO_DISALLOW_COPY_AND_ASSIGN(TryThread
);
185 TEST(MutexTest
, TryLock
) {
188 // |TryLock()| should succeed -- we don't have the lock.
190 TryThread
thread(&mutex
);
193 EXPECT_TRUE(thread
.try_lock_succeeded());
197 ASSERT_TRUE(mutex
.TryLock());
199 // Now it should fail.
201 TryThread
thread(&mutex
);
204 EXPECT_FALSE(thread
.try_lock_succeeded());
210 // It should succeed again.
212 TryThread
thread(&mutex
);
215 EXPECT_TRUE(thread
.try_lock_succeeded());
220 // Tests of assertions for Debug builds.
222 // Test |AssertHeld()| (which is an actual user API).
223 TEST(MutexTest
, DebugAssertHeldFailure
) {
225 EXPECT_DEATH_IF_SUPPORTED(mutex
.AssertHeld(), "");
228 // Test other consistency checks.
229 TEST(MutexTest
, DebugAssertionFailures
) {
230 // Unlock without lock held.
231 EXPECT_DEATH_IF_SUPPORTED({
236 // Lock with lock held (on same thread).
237 EXPECT_DEATH_IF_SUPPORTED({
243 // Try lock with lock held.
244 EXPECT_DEATH_IF_SUPPORTED({
250 // Destroy lock with lock held.
251 EXPECT_DEATH_IF_SUPPORTED({
256 #endif // !defined(NDEBUG)