xref: /aosp_15_r20/external/cronet/base/task/common/checked_lock_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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