1 // Copyright 2016 The Chromium Authors
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/common/checked_lock.h"
6
7 #include <stdlib.h>
8
9 #include "base/compiler_specific.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/rand_util.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/test/gtest_util.h"
14 #include "base/threading/platform_thread.h"
15 #include "base/threading/simple_thread.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19 namespace internal {
20 namespace {
21
22 // Adapted from base::Lock's BasicLockTestThread to make sure
23 // Acquire()/Release() don't crash.
24 class BasicLockTestThread : public SimpleThread {
25 public:
BasicLockTestThread(CheckedLock * lock)26 explicit BasicLockTestThread(CheckedLock* lock)
27 : SimpleThread("BasicLockTestThread"), lock_(lock), acquired_(0) {}
28
29 BasicLockTestThread(const BasicLockTestThread&) = delete;
30 BasicLockTestThread& operator=(const BasicLockTestThread&) = delete;
31
acquired() const32 int acquired() const { return acquired_; }
33
34 private:
Run()35 void Run() override {
36 for (int i = 0; i < 10; i++) {
37 lock_->Acquire();
38 acquired_++;
39 lock_->Release();
40 }
41 for (int i = 0; i < 10; i++) {
42 lock_->Acquire();
43 acquired_++;
44 PlatformThread::Sleep(Milliseconds(base::RandInt(0, 19)));
45 lock_->Release();
46 }
47 }
48
49 const raw_ptr<CheckedLock> lock_;
50 int acquired_;
51 };
52
53 class BasicLockAcquireAndWaitThread : public SimpleThread {
54 public:
BasicLockAcquireAndWaitThread(CheckedLock * lock)55 explicit BasicLockAcquireAndWaitThread(CheckedLock* lock)
56 : SimpleThread("BasicLockAcquireAndWaitThread"),
57 lock_(lock),
58 lock_acquire_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
59 WaitableEvent::InitialState::NOT_SIGNALED),
60 main_thread_continue_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
61 WaitableEvent::InitialState::NOT_SIGNALED) {
62 }
63
64 BasicLockAcquireAndWaitThread(const BasicLockAcquireAndWaitThread&) = delete;
65 BasicLockAcquireAndWaitThread& operator=(
66 const BasicLockAcquireAndWaitThread&) = delete;
67
WaitForLockAcquisition()68 void WaitForLockAcquisition() { lock_acquire_event_.Wait(); }
69
ContinueMain()70 void ContinueMain() { main_thread_continue_event_.Signal(); }
71
72 private:
Run()73 void Run() override {
74 lock_->Acquire();
75 lock_acquire_event_.Signal();
76 main_thread_continue_event_.Wait();
77 lock_->Release();
78 }
79
80 const raw_ptr<CheckedLock> lock_;
81 WaitableEvent lock_acquire_event_;
82 WaitableEvent main_thread_continue_event_;
83 };
84
85 } // namespace
86
TEST(CheckedLockTest,Basic)87 TEST(CheckedLockTest, Basic) {
88 CheckedLock lock;
89 BasicLockTestThread thread(&lock);
90
91 thread.Start();
92
93 int acquired = 0;
94 for (int i = 0; i < 5; i++) {
95 lock.Acquire();
96 acquired++;
97 lock.Release();
98 }
99 for (int i = 0; i < 10; i++) {
100 lock.Acquire();
101 acquired++;
102 PlatformThread::Sleep(Milliseconds(base::RandInt(0, 19)));
103 lock.Release();
104 }
105 for (int i = 0; i < 5; i++) {
106 lock.Acquire();
107 acquired++;
108 PlatformThread::Sleep(Milliseconds(base::RandInt(0, 19)));
109 lock.Release();
110 }
111
112 thread.Join();
113
114 EXPECT_EQ(acquired, 20);
115 EXPECT_EQ(thread.acquired(), 20);
116 }
117
TEST(CheckedLockTest,AcquirePredecessor)118 TEST(CheckedLockTest, AcquirePredecessor) {
119 CheckedLock predecessor;
120 CheckedLock lock(&predecessor);
121 predecessor.Acquire();
122 lock.Acquire();
123 lock.Release();
124 predecessor.Release();
125 }
126
127 // Here and below, disable thread safety analysis, otherwise our death tests do
128 // not compile (the issues are caught at compile time).
TEST(CheckedLockTest,AcquirePredecessorWrongOrder)129 TEST(CheckedLockTest, AcquirePredecessorWrongOrder)
130 NO_THREAD_SAFETY_ANALYSIS {
131 CheckedLock predecessor;
132 CheckedLock lock(&predecessor);
133 EXPECT_DCHECK_DEATH({
134 lock.Acquire();
135 predecessor.Acquire();
136 });
137 }
138
TEST(CheckedLockTest,AcquireNonPredecessor)139 TEST(CheckedLockTest, AcquireNonPredecessor) NO_THREAD_SAFETY_ANALYSIS {
140 CheckedLock lock1;
141 CheckedLock lock2;
142 EXPECT_DCHECK_DEATH({
143 lock1.Acquire();
144 lock2.Acquire();
145 });
146 }
147
TEST(CheckedLockTest,AcquireMultipleLocksInOrder)148 TEST(CheckedLockTest, AcquireMultipleLocksInOrder) {
149 CheckedLock lock1;
150 CheckedLock lock2(&lock1);
151 CheckedLock lock3(&lock2);
152 lock1.Acquire();
153 lock2.Acquire();
154 lock3.Acquire();
155 lock3.Release();
156 lock2.Release();
157 lock1.Release();
158 }
159
TEST(CheckedLockTest,AcquireMultipleLocksInTheMiddleOfAChain)160 TEST(CheckedLockTest, AcquireMultipleLocksInTheMiddleOfAChain) {
161 CheckedLock lock1;
162 CheckedLock lock2(&lock1);
163 CheckedLock lock3(&lock2);
164 lock2.Acquire();
165 lock3.Acquire();
166 lock3.Release();
167 lock2.Release();
168 }
169
TEST(CheckedLockTest,AcquireMultipleLocksNoTransitivity)170 TEST(CheckedLockTest, AcquireMultipleLocksNoTransitivity)
171 NO_THREAD_SAFETY_ANALYSIS {
172 CheckedLock lock1;
173 CheckedLock lock2(&lock1);
174 CheckedLock lock3(&lock2);
175 EXPECT_DCHECK_DEATH({
176 lock1.Acquire();
177 lock3.Acquire();
178 });
179 }
180
TEST(CheckedLockTest,AcquireLocksDifferentThreadsSafely)181 TEST(CheckedLockTest, AcquireLocksDifferentThreadsSafely) {
182 CheckedLock lock1;
183 CheckedLock 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
TEST(CheckedLockTest,AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst)194 TEST(CheckedLockTest,
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 CheckedLock predecessor;
203 CheckedLock 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
TEST(CheckedLockTest,AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast)213 TEST(CheckedLockTest,
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 CheckedLock predecessor;
222 CheckedLock 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
TEST(CheckedLockTest,AcquireLocksWithPredecessorDifferentThreadsSafelyNoInterference)232 TEST(CheckedLockTest,
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 CheckedLock predecessor;
244 CheckedLock lock(&predecessor);
245 predecessor.Acquire();
246 CheckedLock 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
TEST(CheckedLockTest,SelfReferentialLock)257 TEST(CheckedLockTest, SelfReferentialLock) {
258 struct SelfReferentialLock {
259 SelfReferentialLock() : lock(&lock) {}
260
261 CheckedLock lock;
262 };
263
264 EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; });
265 }
266
TEST(CheckedLockTest,PredecessorCycle)267 TEST(CheckedLockTest, PredecessorCycle) {
268 struct LockCycle {
269 LockCycle() : lock1(&lock2), lock2(&lock1) {}
270
271 CheckedLock lock1;
272 CheckedLock lock2;
273 };
274
275 EXPECT_DCHECK_DEATH({ LockCycle cycle; });
276 }
277
TEST(CheckedLockTest,PredecessorLongerCycle)278 TEST(CheckedLockTest, PredecessorLongerCycle) {
279 struct LockCycle {
280 LockCycle()
281 : lock1(&lock5),
282 lock2(&lock1),
283 lock3(&lock2),
284 lock4(&lock3),
285 lock5(&lock4) {}
286
287 CheckedLock lock1;
288 CheckedLock lock2;
289 CheckedLock lock3;
290 CheckedLock lock4;
291 CheckedLock lock5;
292 };
293
294 EXPECT_DCHECK_DEATH({ LockCycle cycle; });
295 }
296
TEST(CheckedLockTest,AcquireLockAfterUniversalPredecessor)297 TEST(CheckedLockTest, AcquireLockAfterUniversalPredecessor) {
298 // Acquisition of a universal-predecessor lock should not prevent acquisition
299 // of a CheckedLock after it.
300 CheckedLock universal_predecessor((UniversalPredecessor()));
301 CheckedLock lock;
302
303 universal_predecessor.Acquire();
304 lock.Acquire();
305 lock.Release();
306 universal_predecessor.Release();
307 }
308
TEST(CheckedLockTest,AcquireMultipleLocksAfterUniversalPredecessor)309 TEST(CheckedLockTest, AcquireMultipleLocksAfterUniversalPredecessor)
310 NO_THREAD_SAFETY_ANALYSIS {
311 // Acquisition of a universal-predecessor lock does not affect acquisition
312 // rules for locks beyond the one acquired directly after it.
313 CheckedLock universal_predecessor{UniversalPredecessor()};
314 CheckedLock lock;
315 CheckedLock lock2(&lock);
316 CheckedLock lock3;
317
318 universal_predecessor.Acquire();
319 lock.Acquire();
320 lock2.Acquire();
321 lock2.Release();
322 lock.Release();
323 universal_predecessor.Release();
324
325 EXPECT_DCHECK_DEATH({
326 universal_predecessor.Acquire();
327 lock.Acquire();
328 lock3.Acquire();
329 });
330 }
331
TEST(CheckedLockTest,AcquireUniversalPredecessorAfterLock)332 TEST(CheckedLockTest, AcquireUniversalPredecessorAfterLock)
333 NO_THREAD_SAFETY_ANALYSIS {
334 // A universal-predecessor lock may not be acquired after any other lock.
335 CheckedLock universal_predecessor{UniversalPredecessor()};
336 CheckedLock lock;
337
338 EXPECT_DCHECK_DEATH({
339 lock.Acquire();
340 universal_predecessor.Acquire();
341 });
342 }
343
TEST(CheckedLockTest,AcquireUniversalPredecessorAfterUniversalPredecessor)344 TEST(CheckedLockTest, AcquireUniversalPredecessorAfterUniversalPredecessor)
345 NO_THREAD_SAFETY_ANALYSIS {
346 // A universal-predecessor lock may not be acquired after any other lock, not
347 // even another universal predecessor.
348 CheckedLock universal_predecessor{UniversalPredecessor()};
349 CheckedLock universal_predecessor2{UniversalPredecessor()};
350
351 EXPECT_DCHECK_DEATH({
352 universal_predecessor.Acquire();
353 universal_predecessor2.Acquire();
354 });
355 }
356
TEST(CheckedLockTest,AcquireLockBeforeUniversalSuccessor)357 TEST(CheckedLockTest, AcquireLockBeforeUniversalSuccessor) {
358 // Acquisition of a universal-successor lock should be allowed
359 // after any other acquisition.
360 CheckedLock universal_successor{UniversalSuccessor()};
361 CheckedLock lock;
362
363 lock.Acquire();
364 universal_successor.Acquire();
365 universal_successor.Release();
366 lock.Release();
367 }
368
TEST(CheckedLockTest,AcquireMultipleLocksBeforeAndAfterUniversalSuccessor)369 TEST(CheckedLockTest, AcquireMultipleLocksBeforeAndAfterUniversalSuccessor)
370 NO_THREAD_SAFETY_ANALYSIS {
371 // Acquisition of a universal-successor lock does not affect acquisition
372 // rules for locks beyond the one acquired directly after it.
373 CheckedLock lock;
374 CheckedLock universal_successor{UniversalSuccessor()};
375 CheckedLock lock2;
376
377 lock.Acquire();
378 universal_successor.Acquire();
379 universal_successor.Release();
380 lock.Release();
381
382 EXPECT_DCHECK_DEATH({
383 universal_successor.Acquire();
384 lock2.Acquire();
385 });
386 }
387
TEST(CheckedLockTest,AcquireUniversalSuccessorBeforeLock)388 TEST(CheckedLockTest, AcquireUniversalSuccessorBeforeLock)
389 NO_THREAD_SAFETY_ANALYSIS {
390 // A universal-successor lock may not be acquired before any other lock.
391 CheckedLock universal_successor{UniversalSuccessor()};
392 CheckedLock lock;
393
394 EXPECT_DCHECK_DEATH({
395 universal_successor.Acquire();
396 lock.Acquire();
397 });
398 }
399
TEST(CheckedLockTest,AcquireUniversalSuccessorAfterUniversalSuccessor)400 TEST(CheckedLockTest, AcquireUniversalSuccessorAfterUniversalSuccessor)
401 NO_THREAD_SAFETY_ANALYSIS {
402 // A universal-successor lock may not be acquired before any other lock, not
403 // even another universal successor.
404 CheckedLock universal_successor{UniversalSuccessor()};
405 CheckedLock universal_successor2{UniversalSuccessor()};
406
407 EXPECT_DCHECK_DEATH({
408 universal_successor.Acquire();
409 universal_successor2.Acquire();
410 });
411 }
412
TEST(CheckedLockTest,UniversalSuccessorAsPredecessor)413 TEST(CheckedLockTest, UniversalSuccessorAsPredecessor)
414 NO_THREAD_SAFETY_ANALYSIS {
415 // A universal-successor lock cannot be declared as a predecessor to
416 // any other lock.
417 CheckedLock universal_successor{UniversalSuccessor()};
418 EXPECT_DCHECK_DEATH({ CheckedLock banned_successor(&universal_successor); });
419 }
420
TEST(CheckedLockTest,AssertNoLockHeldOnCurrentThread)421 TEST(CheckedLockTest, AssertNoLockHeldOnCurrentThread) {
422 // AssertNoLockHeldOnCurrentThread() shouldn't fail when no lock is acquired.
423 CheckedLock::AssertNoLockHeldOnCurrentThread();
424
425 // AssertNoLockHeldOnCurrentThread() should fail when a lock is acquired.
426 CheckedLock lock;
427 {
428 CheckedAutoLock auto_lock(lock);
429 EXPECT_DCHECK_DEATH({ CheckedLock::AssertNoLockHeldOnCurrentThread(); });
430 }
431 }
432
433 namespace {
434
435 class MemberGuardedByLock {
436 public:
437 CheckedLock lock_;
438 int value GUARDED_BY(lock_) = 0;
439 };
440
441 } // namespace
442
TEST(CheckedLockTest,AnnotateAcquiredLockAlias)443 TEST(CheckedLockTest, AnnotateAcquiredLockAlias) {
444 MemberGuardedByLock member_guarded_by_lock;
445 CheckedLock* acquired = &member_guarded_by_lock.lock_;
446 CheckedAutoLock auto_lock(*acquired);
447 AnnotateAcquiredLockAlias annotate(*acquired, member_guarded_by_lock.lock_);
448 member_guarded_by_lock.value = 42; // Doesn't compile without |annotate|.
449 }
450
451 } // namespace internal
452 } // namespace base
453