OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "base/task_scheduler/scheduler_lock.h" | |
6 | |
7 #include <stdlib.h> | |
8 | |
9 #include "base/compiler_specific.h" | |
10 #include "base/macros.h" | |
11 #include "base/rand_util.h" | |
12 #include "base/synchronization/waitable_event.h" | |
13 #include "base/threading/platform_thread.h" | |
14 #include "base/threading/simple_thread.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace base { | |
18 namespace internal { | |
19 namespace { | |
20 | |
21 // Death tests misbehave on Android. | |
22 #if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) | |
23 #define EXPECT_DCHECK_DEATH(statement, regex) EXPECT_DEATH(statement, regex) | |
24 #else | |
25 #define EXPECT_DCHECK_DEATH(statement, regex) | |
gab
2016/03/14 18:26:04
Shouldn't this be
#define EXPECT_DCHECK_DEATH(sta
fdoray
2016/03/14 18:55:52
Note that on Posix, the |statement| of EXPECT_DCHE
robliao
2016/03/14 19:09:52
The way we've structured the tests, we expect deat
gab
2016/03/14 19:51:13
Ok, re-lgtm.
PS: Would be nice to confirm that tr
robliao
2016/03/14 19:55:41
From the tests so far, the mobile ones at least do
gab
2016/03/14 20:02:52
I seem to recall a surprising episode on chromium-
robliao
2016/03/14 20:25:07
Sounds good. Feel free to monitor
https://coderevi
robliao
2016/03/14 20:37:13
And the fireworks have started (tests going red),
| |
26 #endif | |
27 | |
28 // Adapted from base::Lock's BasicLockTestThread to make sure | |
29 // Acquire()/Release() don't crash. | |
30 class BasicLockTestThread : public SimpleThread { | |
31 public: | |
32 explicit BasicLockTestThread(SchedulerLock* lock) | |
33 : SimpleThread("BasicLockTestThread"), | |
34 lock_(lock), | |
35 acquired_(0) {} | |
36 | |
37 int acquired() const { return acquired_; } | |
38 | |
39 private: | |
40 void Run() override { | |
41 for (int i = 0; i < 10; i++) { | |
42 lock_->Acquire(); | |
43 acquired_++; | |
44 lock_->Release(); | |
45 } | |
46 for (int i = 0; i < 10; i++) { | |
47 lock_->Acquire(); | |
48 acquired_++; | |
49 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
50 lock_->Release(); | |
51 } | |
52 } | |
53 | |
54 SchedulerLock* const lock_; | |
55 int acquired_; | |
56 | |
57 DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread); | |
58 }; | |
59 | |
60 class BasicLockAcquireAndWaitThread : public SimpleThread { | |
61 public: | |
62 explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock) | |
63 : SimpleThread("BasicLockAcquireAndWaitThread"), | |
64 lock_(lock), | |
65 lock_acquire_event_(false, false), | |
66 main_thread_continue_event_(false, false) {} | |
67 | |
68 void WaitForLockAcquisition() { | |
69 lock_acquire_event_.Wait(); | |
70 } | |
71 | |
72 void ContinueMain() { | |
73 main_thread_continue_event_.Signal(); | |
74 } | |
75 | |
76 private: | |
77 void Run() override { | |
78 lock_->Acquire(); | |
79 lock_acquire_event_.Signal(); | |
80 main_thread_continue_event_.Wait(); | |
81 lock_->Release(); | |
82 } | |
83 | |
84 SchedulerLock* const lock_; | |
85 WaitableEvent lock_acquire_event_; | |
86 WaitableEvent main_thread_continue_event_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(BasicLockAcquireAndWaitThread); | |
89 }; | |
90 | |
91 TEST(TaskSchedulerLock, Basic) { | |
92 SchedulerLock lock; | |
93 BasicLockTestThread thread(&lock); | |
94 | |
95 thread.Start(); | |
96 | |
97 int acquired = 0; | |
98 for (int i = 0; i < 5; i++) { | |
99 lock.Acquire(); | |
100 acquired++; | |
101 lock.Release(); | |
102 } | |
103 for (int i = 0; i < 10; i++) { | |
104 lock.Acquire(); | |
105 acquired++; | |
106 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
107 lock.Release(); | |
108 } | |
109 for (int i = 0; i < 5; i++) { | |
110 lock.Acquire(); | |
111 acquired++; | |
112 PlatformThread::Sleep(TimeDelta::FromMilliseconds(base::RandInt(0, 19))); | |
113 lock.Release(); | |
114 } | |
115 | |
116 thread.Join(); | |
117 | |
118 EXPECT_EQ(acquired, 20); | |
119 EXPECT_EQ(thread.acquired(), 20); | |
120 } | |
121 | |
122 TEST(TaskSchedulerLock, AcquirePredecessor) { | |
123 SchedulerLock predecessor; | |
124 SchedulerLock lock(&predecessor); | |
125 predecessor.Acquire(); | |
126 lock.Acquire(); | |
127 lock.Release(); | |
128 predecessor.Release(); | |
129 } | |
130 | |
131 TEST(TaskSchedulerLock, AcquirePredecessorWrongOrder) { | |
132 SchedulerLock predecessor; | |
133 SchedulerLock lock(&predecessor); | |
134 EXPECT_DCHECK_DEATH({ | |
135 lock.Acquire(); | |
136 predecessor.Acquire(); | |
137 }, ""); | |
138 } | |
139 | |
140 TEST(TaskSchedulerLock, AcquireNonPredecessor) { | |
141 SchedulerLock lock1; | |
142 SchedulerLock lock2; | |
143 EXPECT_DCHECK_DEATH({ | |
144 lock1.Acquire(); | |
145 lock2.Acquire(); | |
146 }, ""); | |
147 } | |
148 | |
149 TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) { | |
150 SchedulerLock lock1; | |
151 SchedulerLock lock2(&lock1); | |
152 SchedulerLock lock3(&lock2); | |
153 lock1.Acquire(); | |
154 lock2.Acquire(); | |
155 lock3.Acquire(); | |
156 lock3.Release(); | |
157 lock2.Release(); | |
158 lock1.Release(); | |
159 } | |
160 | |
161 TEST(TaskSchedulerLock, AcquireMultipleLocksInTheMiddleOfAChain) { | |
162 SchedulerLock lock1; | |
163 SchedulerLock lock2(&lock1); | |
164 SchedulerLock lock3(&lock2); | |
165 lock2.Acquire(); | |
166 lock3.Acquire(); | |
167 lock3.Release(); | |
168 lock2.Release(); | |
169 } | |
170 | |
171 TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) { | |
172 SchedulerLock lock1; | |
173 SchedulerLock lock2(&lock1); | |
174 SchedulerLock lock3(&lock2); | |
175 EXPECT_DCHECK_DEATH({ | |
176 lock1.Acquire(); | |
177 lock3.Acquire(); | |
178 }, ""); | |
179 } | |
180 | |
181 TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) { | |
182 SchedulerLock lock1; | |
183 SchedulerLock lock2; | |
184 BasicLockAcquireAndWaitThread thread(&lock1); | |
185 thread.Start(); | |
186 | |
187 lock2.Acquire(); | |
188 thread.WaitForLockAcquisition(); | |
189 thread.ContinueMain(); | |
190 thread.Join(); | |
191 lock2.Release(); | |
192 } | |
193 | |
194 TEST(TaskSchedulerLock, | |
195 AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst) { | |
196 // A lock and its predecessor may be safely acquired on different threads. | |
197 // This Thread Other Thread | |
198 // predecessor.Acquire() | |
199 // lock.Acquire() | |
200 // predecessor.Release() | |
201 // lock.Release() | |
202 SchedulerLock predecessor; | |
203 SchedulerLock lock(&predecessor); | |
204 predecessor.Acquire(); | |
205 BasicLockAcquireAndWaitThread thread(&lock); | |
206 thread.Start(); | |
207 thread.WaitForLockAcquisition(); | |
208 predecessor.Release(); | |
209 thread.ContinueMain(); | |
210 thread.Join(); | |
211 } | |
212 | |
213 TEST(TaskSchedulerLock, | |
214 AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast) { | |
215 // A lock and its predecessor may be safely acquired on different threads. | |
216 // This Thread Other Thread | |
217 // lock.Acquire() | |
218 // predecessor.Acquire() | |
219 // lock.Release() | |
220 // predecessor.Release() | |
221 SchedulerLock predecessor; | |
222 SchedulerLock lock(&predecessor); | |
223 lock.Acquire(); | |
224 BasicLockAcquireAndWaitThread thread(&predecessor); | |
225 thread.Start(); | |
226 thread.WaitForLockAcquisition(); | |
227 lock.Release(); | |
228 thread.ContinueMain(); | |
229 thread.Join(); | |
230 } | |
231 | |
232 TEST(TaskSchedulerLock, | |
233 AcquireLocksWithPredecessorDifferentThreadsSafelyNoInterference) { | |
234 // Acquisition of an unrelated lock on another thread should not affect a | |
235 // legal lock acquisition with a predecessor on this thread. | |
236 // This Thread Other Thread | |
237 // predecessor.Acquire() | |
238 // unrelated.Acquire() | |
239 // lock.Acquire() | |
240 // unrelated.Release() | |
241 // lock.Release() | |
242 // predecessor.Release(); | |
243 SchedulerLock predecessor; | |
244 SchedulerLock lock(&predecessor); | |
245 predecessor.Acquire(); | |
246 SchedulerLock unrelated; | |
247 BasicLockAcquireAndWaitThread thread(&unrelated); | |
248 thread.Start(); | |
249 thread.WaitForLockAcquisition(); | |
250 lock.Acquire(); | |
251 thread.ContinueMain(); | |
252 thread.Join(); | |
253 lock.Release(); | |
254 predecessor.Release(); | |
255 } | |
256 | |
257 TEST(TaskSchedulerLock, SelfReferentialLock) { | |
258 struct SelfReferentialLock { | |
259 SelfReferentialLock() : lock(&lock) {} | |
260 | |
261 SchedulerLock lock; | |
262 }; | |
263 | |
264 EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; }, ""); | |
265 } | |
266 | |
267 TEST(TaskSchedulerLock, PredecessorCycle) { | |
268 struct LockCycle { | |
269 LockCycle() : lock1(&lock2), lock2(&lock1) {} | |
270 | |
271 SchedulerLock lock1; | |
272 SchedulerLock lock2; | |
273 }; | |
274 | |
275 EXPECT_DCHECK_DEATH({ LockCycle cycle; }, ""); | |
276 } | |
277 | |
278 TEST(TaskSchedulerLock, PredecessorLongerCycle) { | |
279 struct LockCycle { | |
280 LockCycle() | |
281 : lock1(&lock5), | |
282 lock2(&lock1), | |
283 lock3(&lock2), | |
284 lock4(&lock3), | |
285 lock5(&lock4) {} | |
286 | |
287 SchedulerLock lock1; | |
288 SchedulerLock lock2; | |
289 SchedulerLock lock3; | |
290 SchedulerLock lock4; | |
291 SchedulerLock lock5; | |
292 }; | |
293 | |
294 EXPECT_DCHECK_DEATH({ LockCycle cycle; }, ""); | |
295 } | |
296 | |
297 } // namespace | |
298 } // namespace internal | |
299 } // namespace base | |
OLD | NEW |