OLD | NEW |
| (Empty) |
1 // Copyright 2015 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/edk/system/mutex.h" | |
6 | |
7 #include <stdlib.h> | |
8 | |
9 #include <thread> | |
10 | |
11 #include "mojo/edk/system/test/sleep.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 namespace mojo { | |
15 namespace system { | |
16 namespace { | |
17 | |
18 // Sleeps for a "very small" amount of time. | |
19 void EpsilonRandomSleep() { | |
20 test::SleepMilliseconds(static_cast<unsigned>(rand()) % 20u); | |
21 } | |
22 | |
23 // Basic test to make sure that Lock()/Unlock()/TryLock() don't crash ---------- | |
24 | |
25 TEST(MutexTest, Basic) { | |
26 Mutex mutex; | |
27 | |
28 int thread_acquired = 0; | |
29 auto thread = std::thread([&mutex, &thread_acquired]() { | |
30 for (int i = 0; i < 10; i++) { | |
31 mutex.Lock(); | |
32 mutex.AssertHeld(); | |
33 thread_acquired++; | |
34 mutex.Unlock(); | |
35 } | |
36 for (int i = 0; i < 10; i++) { | |
37 mutex.Lock(); | |
38 mutex.AssertHeld(); | |
39 thread_acquired++; | |
40 EpsilonRandomSleep(); | |
41 mutex.Unlock(); | |
42 } | |
43 for (int i = 0; i < 10; i++) { | |
44 if (mutex.TryLock()) { | |
45 mutex.AssertHeld(); | |
46 thread_acquired++; | |
47 EpsilonRandomSleep(); | |
48 mutex.Unlock(); | |
49 } | |
50 } | |
51 }); | |
52 | |
53 int acquired = 0; | |
54 for (int i = 0; i < 5; i++) { | |
55 mutex.Lock(); | |
56 mutex.AssertHeld(); | |
57 acquired++; | |
58 mutex.Unlock(); | |
59 } | |
60 for (int i = 0; i < 10; i++) { | |
61 mutex.Lock(); | |
62 mutex.AssertHeld(); | |
63 acquired++; | |
64 EpsilonRandomSleep(); | |
65 mutex.Unlock(); | |
66 } | |
67 for (int i = 0; i < 10; i++) { | |
68 if (mutex.TryLock()) { | |
69 mutex.AssertHeld(); | |
70 acquired++; | |
71 EpsilonRandomSleep(); | |
72 mutex.Unlock(); | |
73 } | |
74 } | |
75 for (int i = 0; i < 5; i++) { | |
76 mutex.Lock(); | |
77 mutex.AssertHeld(); | |
78 acquired++; | |
79 EpsilonRandomSleep(); | |
80 mutex.Unlock(); | |
81 } | |
82 | |
83 thread.join(); | |
84 | |
85 EXPECT_GE(acquired, 20); | |
86 EXPECT_GE(thread_acquired, 20); | |
87 } | |
88 | |
89 TEST(MutexTest, AssertHeld) { | |
90 Mutex mutex; | |
91 | |
92 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) | |
93 // For non-Debug builds, |AssertHeld()| should do nothing. | |
94 mutex.AssertHeld(); | |
95 #else | |
96 EXPECT_DEATH_IF_SUPPORTED({ mutex.AssertHeld(); }, "Check failed"); | |
97 #endif // defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) | |
98 | |
99 // TODO(vtl): Should also test the case when the mutex is held by another | |
100 // thread, though this is more annoying since it requires synchronization. | |
101 } | |
102 | |
103 // Test that TryLock() works as expected --------------------------------------- | |
104 | |
105 TEST(MutexTest, TryLock) MOJO_NO_THREAD_SAFETY_ANALYSIS { | |
106 Mutex mutex; | |
107 | |
108 ASSERT_TRUE(mutex.TryLock()); | |
109 // We now have the mutex.... | |
110 | |
111 { | |
112 // This thread will not be able to get the mutex. | |
113 auto thread = std::thread([&mutex]() { EXPECT_FALSE(mutex.TryLock()); }); | |
114 thread.join(); | |
115 } | |
116 | |
117 mutex.Unlock(); | |
118 // And now we don't. | |
119 | |
120 { | |
121 // This thread will be able to get it (and then release it). | |
122 auto thread = std::thread([&mutex]() { | |
123 EXPECT_TRUE(mutex.TryLock()); | |
124 mutex.AssertHeld(); | |
125 mutex.Unlock(); | |
126 }); | |
127 thread.join(); | |
128 | |
129 // And we can take it again. | |
130 ASSERT_TRUE(mutex.TryLock()); | |
131 } | |
132 | |
133 mutex.Unlock(); | |
134 } | |
135 | |
136 // Tests that mutexes actually exclude ----------------------------------------- | |
137 | |
138 // We'll call this from both the main thread and secondary threads. | |
139 void DoStuffWithMutex(Mutex* mutex, int* value) { | |
140 for (int i = 0; i < 40; i++) { | |
141 mutex->Lock(); | |
142 int v = *value; | |
143 EpsilonRandomSleep(); | |
144 *value = v + 1; | |
145 mutex->Unlock(); | |
146 } | |
147 } | |
148 | |
149 std::thread MakeMutexTestThread(Mutex* mutex, int* value) { | |
150 return std::thread([mutex, value]() { DoStuffWithMutex(mutex, value); }); | |
151 } | |
152 | |
153 TEST(MutexTest, MutexTwoThreads) { | |
154 Mutex mutex; | |
155 int value = 0; | |
156 | |
157 std::thread thread = MakeMutexTestThread(&mutex, &value); | |
158 | |
159 DoStuffWithMutex(&mutex, &value); | |
160 | |
161 thread.join(); | |
162 | |
163 EXPECT_EQ(2 * 40, value); | |
164 } | |
165 | |
166 TEST(MutexTest, MutexFourThreads) { | |
167 Mutex mutex; | |
168 int value = 0; | |
169 | |
170 std::thread thread1 = MakeMutexTestThread(&mutex, &value); | |
171 std::thread thread2 = MakeMutexTestThread(&mutex, &value); | |
172 std::thread thread3 = MakeMutexTestThread(&mutex, &value); | |
173 | |
174 DoStuffWithMutex(&mutex, &value); | |
175 | |
176 thread1.join(); | |
177 thread2.join(); | |
178 thread3.join(); | |
179 | |
180 EXPECT_EQ(4 * 40, value); | |
181 } | |
182 | |
183 // MutexLocker ----------------------------------------------------------------- | |
184 | |
185 TEST(MutexTest, MutexLocker) { | |
186 Mutex mutex; | |
187 | |
188 { | |
189 MutexLocker locker(&mutex); | |
190 mutex.AssertHeld(); | |
191 } | |
192 | |
193 // The destruction of |locker| should unlock |mutex|. | |
194 ASSERT_TRUE(mutex.TryLock()); | |
195 mutex.AssertHeld(); | |
196 mutex.Unlock(); | |
197 } | |
198 | |
199 } // namespace | |
200 } // namespace system | |
201 } // namespace mojo | |
OLD | NEW |