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

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

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

Powered by Google App Engine
This is Rietveld 408576698