xref: /aosp_15_r20/external/cronet/base/task/common/checked_lock.h (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 #ifndef BASE_TASK_COMMON_CHECKED_LOCK_H_
6 #define BASE_TASK_COMMON_CHECKED_LOCK_H_
7 
8 #include <optional>
9 
10 #include "base/check_op.h"
11 #include "base/dcheck_is_on.h"
12 #include "base/memory/stack_allocated.h"
13 #include "base/synchronization/condition_variable.h"
14 #include "base/synchronization/lock.h"
15 #include "base/task/common/checked_lock_impl.h"
16 #include "base/thread_annotations.h"
17 
18 namespace base {
19 namespace internal {
20 
21 // CheckedLock should be used anywhere a Lock would be used in the base/task
22 // impl. When DCHECK_IS_ON(), lock checking occurs. Otherwise, CheckedLock is
23 // equivalent to base::Lock.
24 //
25 // The shape of CheckedLock is as follows:
26 // CheckedLock()
27 //     Default constructor, no predecessor lock.
28 //     DCHECKs
29 //         On Acquisition if any CheckedLock is acquired on this thread.
30 //             Okay if a universal predecessor is acquired.
31 //
32 // CheckedLock(const CheckedLock* predecessor)
33 //     Constructor that specifies an allowed predecessor for that lock.
34 //     DCHECKs
35 //         On Construction if |predecessor| forms a predecessor lock cycle or
36 //             is a universal successor.
37 //         On Acquisition if the previous lock acquired on the thread is not
38 //             either |predecessor| or a universal predecessor. Okay if there
39 //             was no previous lock acquired.
40 //
41 // CheckedLock(UniversalPredecessor universal_predecessor)
42 //     Constructor for a lock that will allow the acquisition of any lock after
43 //     it, without needing to explicitly be named a predecessor (e.g. a root in
44 //     a lock chain). Can only be acquired if no locks are currently held by
45 //     this thread. DCHECKs
46 //         On Acquisition if any CheckedLock is acquired on this thread.
47 //
48 // CheckedLock(UniversalSuccessor universal_successor)
49 //     Constructor for a lock that will allow its acquisition after any other
50 //     lock, without needing to explicitly name its predecessor (e.g. a leaf in
51 //     a lock chain). Can not be acquired after another UniversalSuccessor lock.
52 //     DCHECKs
53 //         On Acquisition if there was a previously acquired lock on the thread
54 //             and it was also a universal successor.
55 //
56 // void Acquire()
57 //     Acquires the lock.
58 //
59 // void Release()
60 //     Releases the lock.
61 //
62 // void AssertAcquired().
63 //     DCHECKs if the lock is not acquired.
64 //
65 // ConditionVariable CreateConditionVariable()
66 //     Creates a condition variable using this as a lock.
67 
68 #if DCHECK_IS_ON()
69 class LOCKABLE CheckedLock : public CheckedLockImpl {
70  public:
71   CheckedLock() = default;
CheckedLock(const CheckedLock * predecessor)72   explicit CheckedLock(const CheckedLock* predecessor)
73       : CheckedLockImpl(predecessor) {}
CheckedLock(UniversalPredecessor universal_predecessor)74   explicit CheckedLock(UniversalPredecessor universal_predecessor)
75       : CheckedLockImpl(universal_predecessor) {}
CheckedLock(UniversalSuccessor universal_successor)76   explicit CheckedLock(UniversalSuccessor universal_successor)
77       : CheckedLockImpl(universal_successor) {}
78 };
79 #else   // DCHECK_IS_ON()
80 class LOCKABLE CheckedLock : public Lock {
81  public:
82   CheckedLock() = default;
83   explicit CheckedLock(const CheckedLock*) {}
84   explicit CheckedLock(UniversalPredecessor) {}
85   explicit CheckedLock(UniversalSuccessor) {}
86   static void AssertNoLockHeldOnCurrentThread() {}
87 
88   ConditionVariable CreateConditionVariable() {
89     return ConditionVariable(this);
90   }
91   void CreateConditionVariableAndEmplace(
92       std::optional<ConditionVariable>& opt) {
93     opt.emplace(this);
94   }
95 };
96 #endif  // DCHECK_IS_ON()
97 
98 // Provides the same functionality as base::AutoLock for CheckedLock.
99 using CheckedAutoLock = internal::BasicAutoLock<CheckedLock>;
100 
101 // Provides the same functionality as base::AutoUnlock for CheckedLock.
102 using CheckedAutoUnlock = internal::BasicAutoUnlock<CheckedLock>;
103 
104 // Provides the same functionality as base::AutoLockMaybe for CheckedLock.
105 using CheckedAutoLockMaybe = internal::BasicAutoLockMaybe<CheckedLock>;
106 
107 // Informs the clang thread safety analysis that an aliased lock is acquired.
108 // Because the clang thread safety analysis doesn't understand aliased locks
109 // [1], this code wouldn't compile without AnnotateAcquiredLockAlias:
110 //
111 // class Example {
112 //  public:
113 //    CheckedLock lock_;
114 //    int value = 0 GUARDED_BY(lock_);
115 // };
116 //
117 // Example example;
118 // CheckedLock* acquired = &example.lock_;
119 // CheckedAutoLock auto_lock(*acquired);
120 // AnnotateAcquiredLockAlias annotate(*acquired, example.lock_);
121 // example.value = 42;  // Doesn't compile without |annotate|.
122 //
123 // [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis
124 class SCOPED_LOCKABLE AnnotateAcquiredLockAlias {
125   STACK_ALLOCATED();
126 
127  public:
128   // |acquired_lock| is an acquired lock. |lock_alias| is an alias of
129   // |acquired_lock|.
AnnotateAcquiredLockAlias(const CheckedLock & acquired_lock,const CheckedLock & lock_alias)130   AnnotateAcquiredLockAlias(const CheckedLock& acquired_lock,
131                             const CheckedLock& lock_alias)
132       EXCLUSIVE_LOCK_FUNCTION(lock_alias)
133       : acquired_lock_(acquired_lock) {
134     DCHECK_EQ(&acquired_lock, &lock_alias);
135     acquired_lock_.AssertAcquired();
136   }
137 
138   AnnotateAcquiredLockAlias(const AnnotateAcquiredLockAlias&) = delete;
139   AnnotateAcquiredLockAlias& operator=(const AnnotateAcquiredLockAlias&) =
140       delete;
141 
UNLOCK_FUNCTION()142   ~AnnotateAcquiredLockAlias() UNLOCK_FUNCTION() {
143     acquired_lock_.AssertAcquired();
144   }
145 
146  private:
147   const CheckedLock& acquired_lock_;
148 };
149 
150 }  // namespace internal
151 }  // namespace base
152 
153 #endif  // BASE_TASK_COMMON_CHECKED_LOCK_H_
154