• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
9 
10 #include "base/check_op.h"
11 #include "base/dcheck_is_on.h"
12 #include "base/memory/raw_ref.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 // std::unique_ptr<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   std::unique_ptr<ConditionVariable> CreateConditionVariable() {
89     return std::unique_ptr<ConditionVariable>(new ConditionVariable(this));
90   }
91 };
92 #endif  // DCHECK_IS_ON()
93 
94 // Provides the same functionality as base::AutoLock for CheckedLock.
95 using CheckedAutoLock = internal::BasicAutoLock<CheckedLock>;
96 
97 // Provides the same functionality as base::AutoUnlock for CheckedLock.
98 using CheckedAutoUnlock = internal::BasicAutoUnlock<CheckedLock>;
99 
100 // Provides the same functionality as base::AutoLockMaybe for CheckedLock.
101 using CheckedAutoLockMaybe = internal::BasicAutoLockMaybe<CheckedLock>;
102 
103 // Informs the clang thread safety analysis that an aliased lock is acquired.
104 // Because the clang thread safety analysis doesn't understand aliased locks
105 // [1], this code wouldn't compile without AnnotateAcquiredLockAlias:
106 //
107 // class Example {
108 //  public:
109 //    CheckedLock lock_;
110 //    int value = 0 GUARDED_BY(lock_);
111 // };
112 //
113 // Example example;
114 // CheckedLock* acquired = &example.lock_;
115 // CheckedAutoLock auto_lock(*acquired);
116 // AnnotateAcquiredLockAlias annotate(*acquired, example.lock_);
117 // example.value = 42;  // Doesn't compile without |annotate|.
118 //
119 // [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis
120 class SCOPED_LOCKABLE AnnotateAcquiredLockAlias {
121  public:
122   // |acquired_lock| is an acquired lock. |lock_alias| is an alias of
123   // |acquired_lock|.
AnnotateAcquiredLockAlias(const CheckedLock & acquired_lock,const CheckedLock & lock_alias)124   AnnotateAcquiredLockAlias(const CheckedLock& acquired_lock,
125                             const CheckedLock& lock_alias)
126       EXCLUSIVE_LOCK_FUNCTION(lock_alias)
127       : acquired_lock_(acquired_lock) {
128     DCHECK_EQ(&acquired_lock, &lock_alias);
129     acquired_lock_->AssertAcquired();
130   }
131 
132   AnnotateAcquiredLockAlias(const AnnotateAcquiredLockAlias&) = delete;
133   AnnotateAcquiredLockAlias& operator=(const AnnotateAcquiredLockAlias&) =
134       delete;
135 
UNLOCK_FUNCTION()136   ~AnnotateAcquiredLockAlias() UNLOCK_FUNCTION() {
137     acquired_lock_->AssertAcquired();
138   }
139 
140  private:
141   const raw_ref<const CheckedLock> acquired_lock_;
142 };
143 
144 }  // namespace internal
145 }  // namespace base
146 
147 #endif  // BASE_TASK_COMMON_CHECKED_LOCK_H_
148