Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(203)

Side by Side Diff: mojo/public/utility/tests/mutex_unittest.cc

Issue 217443002: Mojo: Move mojo/public/utility to mojo/public/cpp/utility. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mojo/public/utility/run_loop_handler.h ('k') | mojo/public/utility/tests/run_loop_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "mojo/public/utility/mutex.h"
6
7 #include <stdlib.h> // For |rand()|.
8 #include <time.h> // For |nanosleep()| (defined by POSIX).
9
10 #include <vector>
11
12 #include "mojo/public/cpp/system/macros.h"
13 #include "mojo/public/utility/thread.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace mojo {
17 namespace {
18
19 TEST(MutexTest, TrivialSingleThreaded) {
20 Mutex mutex;
21
22 mutex.Lock();
23 mutex.AssertHeld();
24 mutex.Unlock();
25
26 EXPECT_TRUE(mutex.TryLock());
27 mutex.AssertHeld();
28 mutex.Unlock();
29
30 {
31 MutexLock lock(&mutex);
32 mutex.AssertHeld();
33 }
34
35 EXPECT_TRUE(mutex.TryLock());
36 mutex.Unlock();
37 }
38
39 class Fiddler {
40 public:
41 enum Type { kTypeLock, kTypeTry };
42 Fiddler(size_t times_to_lock,
43 Type type,
44 bool should_sleep,
45 Mutex* mutex,
46 int* shared_value)
47 : times_to_lock_(times_to_lock),
48 type_(type),
49 should_sleep_(should_sleep),
50 mutex_(mutex),
51 shared_value_(shared_value) {
52 }
53
54 ~Fiddler() {
55 }
56
57 void Fiddle() {
58 for (size_t i = 0; i < times_to_lock_;) {
59 switch (type_) {
60 case kTypeLock: {
61 mutex_->Lock();
62 int old_shared_value = *shared_value_;
63 if (should_sleep_)
64 SleepALittle();
65 *shared_value_ = old_shared_value + 1;
66 mutex_->Unlock();
67 i++;
68 break;
69 }
70 case kTypeTry:
71 if (mutex_->TryLock()) {
72 int old_shared_value = *shared_value_;
73 if (should_sleep_)
74 SleepALittle();
75 *shared_value_ = old_shared_value + 1;
76 mutex_->Unlock();
77 i++;
78 } else {
79 SleepALittle(); // Don't spin.
80 }
81 break;
82 }
83 }
84 }
85
86 private:
87 static void SleepALittle() {
88 static const long kNanosPerMilli = 1000000;
89 struct timespec req = {
90 0, // Seconds.
91 (rand() % 10) * kNanosPerMilli // Nanoseconds.
92 };
93 int rv MOJO_ALLOW_UNUSED = nanosleep(&req, NULL);
94 assert(rv == 0);
95 }
96
97 const size_t times_to_lock_;
98 const Type type_;
99 const bool should_sleep_;
100 Mutex* const mutex_;
101 int* const shared_value_;
102
103 MOJO_DISALLOW_COPY_AND_ASSIGN(Fiddler);
104 };
105
106 class FiddlerThread : public Thread {
107 public:
108 // Takes ownership of |fiddler|.
109 FiddlerThread(Fiddler* fiddler)
110 : fiddler_(fiddler) {
111 }
112
113 virtual ~FiddlerThread() {
114 delete fiddler_;
115 }
116
117 virtual void Run() MOJO_OVERRIDE {
118 fiddler_->Fiddle();
119 }
120
121 private:
122 Fiddler* const fiddler_;
123
124 MOJO_DISALLOW_COPY_AND_ASSIGN(FiddlerThread);
125 };
126
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);
132
133 Mutex mutex;
134 int shared_value = 0;
135
136 std::vector<FiddlerThread*> fiddler_threads;
137
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)));
147 }
148
149 for (size_t i = 0; i < kNumThreads; i++)
150 fiddler_threads[i]->Start();
151
152 // Do some fiddling ourselves.
153 Fiddler(kTimesToLockEach, Fiddler::kTypeLock, true, &mutex, &shared_value)
154 .Fiddle();
155
156 // Join.
157 for (size_t i = 0; i < kNumThreads; i++)
158 fiddler_threads[i]->Join();
159
160 EXPECT_EQ(static_cast<int>(kNumThreads + 1) * kTimesToLockEach, shared_value);
161
162 // Delete.
163 for (size_t i = 0; i < kNumThreads; i++)
164 delete fiddler_threads[i];
165 fiddler_threads.clear();
166 }
167
168 class TryThread : public Thread {
169 public:
170 explicit TryThread(Mutex* mutex) : mutex_(mutex), try_lock_succeeded_() {}
171 virtual ~TryThread() {}
172
173 virtual void Run() MOJO_OVERRIDE {
174 try_lock_succeeded_ = mutex_->TryLock();
175 if (try_lock_succeeded_)
176 mutex_->Unlock();
177 }
178
179 bool try_lock_succeeded() const { return try_lock_succeeded_; }
180
181 private:
182 Mutex* const mutex_;
183 bool try_lock_succeeded_;
184
185 MOJO_DISALLOW_COPY_AND_ASSIGN(TryThread);
186 };
187
188 TEST(MutexTest, TryLock) {
189 Mutex mutex;
190
191 // |TryLock()| should succeed -- we don't have the lock.
192 {
193 TryThread thread(&mutex);
194 thread.Start();
195 thread.Join();
196 EXPECT_TRUE(thread.try_lock_succeeded());
197 }
198
199 // Take the lock.
200 ASSERT_TRUE(mutex.TryLock());
201
202 // Now it should fail.
203 {
204 TryThread thread(&mutex);
205 thread.Start();
206 thread.Join();
207 EXPECT_FALSE(thread.try_lock_succeeded());
208 }
209
210 // Release the lock.
211 mutex.Unlock();
212
213 // It should succeed again.
214 {
215 TryThread thread(&mutex);
216 thread.Start();
217 thread.Join();
218 EXPECT_TRUE(thread.try_lock_succeeded());
219 }
220 }
221
222
223 // Tests of assertions for Debug builds.
224 #if !defined(NDEBUG)
225 // Test |AssertHeld()| (which is an actual user API).
226 TEST(MutexTest, DebugAssertHeldFailure) {
227 Mutex mutex;
228 EXPECT_DEATH(mutex.AssertHeld(), "");
229 }
230
231 // Test other consistency checks.
232 TEST(MutexTest, DebugAssertionFailures) {
233 // Unlock without lock held.
234 EXPECT_DEATH({
235 Mutex mutex;
236 mutex.Unlock();
237 }, "");
238
239 // Lock with lock held (on same thread).
240 EXPECT_DEATH({
241 Mutex mutex;
242 mutex.Lock();
243 mutex.Lock();
244 }, "");
245
246 // Try lock with lock held.
247 EXPECT_DEATH({
248 Mutex mutex;
249 mutex.Lock();
250 mutex.TryLock();
251 }, "");
252
253 // Destroy lock with lock held.
254 EXPECT_DEATH({
255 Mutex mutex;
256 mutex.Lock();
257 }, "");
258 }
259 #endif // !defined(NDEBUG)
260
261 } // namespace
262 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/utility/run_loop_handler.h ('k') | mojo/public/utility/tests/run_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698