1 // Copyright 2018 The Fuchsia 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 #pragma once
6 
7 #include <zircon/compiler.h>
8 
9 #include <fbl/type_info.h>
10 
11 #include <lockdep/common.h>
12 #include <lockdep/global_reference.h>
13 #include <lockdep/lock_class_state.h>
14 #include <lockdep/lock_traits.h>
15 #include <lockdep/thread_lock_state.h>
16 
17 namespace lockdep {
18 
19 // Looks up a lock traits type using ADL to perform cross-namespace matching.
20 // This alias works in concert with the macro LOCK_DEP_TRAITS(type, flags) to
21 // find the defined lock traits for a lock, even when defined in a different
22 // namespace.
23 template <typename T>
24 using LookupLockTraits =
25     decltype(LOCK_DEP_GetLockTraits(static_cast<T*>(nullptr)));
26 
27 // Base lock traits type. If a type has not been tagged with the
28 // LOCK_DEP_TRAITS() then this base type provides the default flags for the lock
29 // type.
30 template <typename T, typename = void>
31 struct LockTraits {
32     static constexpr LockFlags Flags = LockFlagsNone;
33 };
34 // Returns the flags for a lock type when the type is tagged with
35 // LOCK_DEP_TRAITS(type, flags).
36 template <typename T>
37 struct LockTraits<T, fbl::void_t<LookupLockTraits<T>>> {
38     static constexpr LockFlags Flags = LookupLockTraits<T>::Flags;
39 };
40 
41 // Singleton type that represents a lock class. Each template instantiation
42 // represents an independent, unique lock class. This type maintains a global
43 // dependency set that tracks which other lock classes have been observed
44 // being held prior to acquisitions of this lock class. This type is only used
45 // when lock validation is enabled, otherwise DummyLockClass takes its place.
46 template <typename Class, typename LockType, size_t Index, LockFlags Flags>
47 class LockClass {
48 public:
49     // Returns the unique lock class id for this lock class.
50     static LockClassId Id() {
51         return lock_class_state_.id();
52     }
53 
54     // Returns the LockClassState instance for this lock class.
55     static LockClassState* GetLockClassState() { return &lock_class_state_; }
56 
57 private:
58     LockClass() = default;
59     ~LockClass() = default;
60     LockClass(const LockClass&) = delete;
61     void operator=(const LockClass&) = delete;
62 
63     // Returns the name of this lock class.
64     constexpr static const char* GetName() {
65         return fbl::TypeInfo<LockClass>::Name();
66     }
67 
68     // Lock free dependency set that tracks which lock classes have been observed
69     // being held prior to acquisitions of this lock class.
70     static LockDependencySet dependency_set_;
71 
72     // This static member serves a dual role:
73     //  1. Stores the id, name, and pointer to dependency set for this lock class.
74     //  2. The address of this member serves as the unique id for this lock class.
75     static LockClassState lock_class_state_;
76 };
77 
78 // Initializes the value of the lock class state with the id, typeid name, and
79 // dependency set of the lock class. This results in a global initializer that
80 // performs trivial assignment.
81 template <typename Class, typename LockType, size_t Index, LockFlags Flags>
82 LockClassState LockClass<Class, LockType, Index, Flags>::lock_class_state_ = {
83     LockClass<Class, LockType, Index, Flags>::GetName(),
84     &LockClass<Class, LockType, Index, Flags>::dependency_set_,
85     static_cast<LockFlags>(LockTraits<LockType>::Flags | Flags)};
86 
87 // The storage for this static member is allocated as zeroed memory.
88 template <typename Class, typename LockType, size_t Index, LockFlags Flags>
89 LockDependencySet LockClass<Class, LockType, Index, Flags>::dependency_set_;
90 
91 // Dummy type used in place of LockClass when validation is disabled. This type
92 // does not create static dependency tracking structures that LockClass does.
93 struct DummyLockClass {
94     static LockClassId Id() { return kInvalidLockClassId; }
95 };
96 
97 // Alias that selects LockClass<Class, LockType, Index, Flags> when validation
98 // is enabled or DummyLockClass when validation is disabled.
99 template <typename Class, typename LockType, size_t Index, LockFlags Flags>
100 using ConditionalLockClass = IfLockValidationEnabled<
101     LockClass<Class, LockType, Index, Flags>, DummyLockClass>;
102 
103 // Base lock wrapper type that provides the essential interface required by
104 // Guard<LockType, Option> to perform locking and validation. This type wraps
105 // an instance of LockType that is used to perform the actual synchronization.
106 // When lock validation is enabled this type also stores the LockClassId for
107 // the lock class this lock belongs to.
108 //
109 // The "lock class" that each lock belongs to is created by each unique
110 // instantiation of the types LockDep<Class, LockType, Index> or
111 // SingletonLockDep<Class, LockType, LockFlags> below. These types subclass
112 // Lock<LockType> to provide type erasure required when virtual accessors are
113 // used to specify capabilities to Clang static lock analysis.
114 //
115 // For example, the lock_ members of LockableType and AnotherLockableType below
116 // are different types due to how LockDep<> instruments the lock members.
117 // Both unique LockDep<> instantiations derive from the same Lock<LockType>,
118 // providing a common capability type (erasing the LockDep<> type) that may be
119 // used in static lock annotations with the expression "get_lock()".
120 //
121 //  struct LockableInterface {
122 //      virtual ~LockableInterface = 0;
123 //      virtual Lock<fbl::Mutex>* get_lock() = 0;
124 //      virtual void Clear() __TA_REQUIRES(get_lock()) = 0;
125 //  };
126 //
127 //  class LockableType : public LockableInterface {
128 //  public:
129 //      LockableType() = default;
130 //      ~LockableType() override = default;
131 //
132 //      Lock<fbl::Mutex>* get_lock() override { return &lock_; }
133 //
134 //      void Clear() override { count_ = 0; }
135 //
136 //      void Increment() {
137 //          Guard<fbl::Mutex> guard{get_lock()};
138 //          count_++;
139 //      }
140 //
141 //
142 //  private:
143 //      LOCK_DEP_INSTRUMENT(LockableType, fbl::Mutex) lock_;
144 //      int count_ __TA_GUARDED(get_lock()) {0};
145 //  };
146 //
147 //  class AnotherLockableType : public LockableInterface {
148 //  public:
149 //      AnotherLockableType() = default;
150 //      ~AnotherLockableType() override = default;
151 //
152 //      Lock<fbl::Mutex>* get_lock() override { return &lock_; }
153 //
154 //      void Clear() override { test_.clear(); }
155 //
156 //      void Append(const std::string& string) {
157 //          Guard<fbl::Mutex> guard{get_lock()};
158 //          text_.append(string)
159 //      }
160 //
161 //
162 //  private:
163 //      LOCK_DEP_INSTRUMENT(AnotherLockableType, fbl::Mutex) lock_;
164 //      std::string text_ __TA_GUARDED(get_lock()) {};
165 //  };
166 //
167 template <typename LockType>
168 class __TA_CAPABILITY("mutex") Lock {
169 public:
170     Lock(Lock&&) = delete;
171     Lock(const Lock&) = delete;
172     Lock& operator=(Lock&&) = delete;
173     Lock& operator=(const Lock&) = delete;
174 
175     ~Lock() = default;
176 
177     // Provides direct access to the underlying lock. Care should be taken when
178     // manipulating the underlying lock. Incorrect manipulation could confuse
179     // the validator, trigger lock assertions, and/or deadlock.
180     LockType& lock() { return lock_; }
181 
182     // Returns the capability of the underlying lock. This is expected by Guard
183     // as an additional static assertion target.
184     LockType& capability() __TA_RETURN_CAPABILITY(lock_) { return lock_; }
185 
186 protected:
187     // Initializes the Lock instance with the given LockClassId and passes any
188     // additional arguments to the underlying lock constructor.
189     template <typename... Args>
190     constexpr Lock(LockClassId id, Args&&... args)
191         : id_{id}, lock_(fbl::forward<Args>(args)...) {}
192 
193 private:
194     template <typename, typename>
195     friend class Guard;
196     template <size_t, typename, typename>
197     friend class GuardMultiple;
198 
199     // Returns the LockClassId of the lock class this lock belongs to.
200     LockClassId id() const { return id_.value(); }
201 
202     // Value type that stores the LockClassId for this lock when validation is
203     // enabled.
204     struct Value {
205         LockClassId value_;
206         LockClassId value() const { return value_; }
207     };
208 
209     // Dummy type that stores nothing when validation is disabled.
210     struct Dummy {
211         Dummy(LockClassId) {}
212         LockClassId value() const { return kInvalidLockClassId; }
213     };
214 
215     // Selects between Value or Dummy based on whether validation is enabled.
216     using IdValue = IfLockValidationEnabled<Value, Dummy>;
217 
218     // Stores the lock class id of this lock when validation is enabled.
219     IdValue id_;
220 
221     // The underlying lock managed by this dependency tracking wrapper.
222     LockType lock_;
223 };
224 
225 // Specialization of Lock<LockType> that wraps a static/global raw lock. This
226 // type permits creating a tracked alias of a raw lock of type LockType that
227 // has static storage duration, with either external or internal linkage.
228 //
229 // This type supports transitioning from C-compatible APIs to full C++.
230 template <typename LockType, LockType& Reference>
231 class __TA_CAPABILITY("mutex") Lock<GlobalReference<LockType, Reference>> {
232 public:
233     Lock(Lock&&) = delete;
234     Lock(const Lock&) = delete;
235     Lock& operator=(Lock&&) = delete;
236     Lock& operator=(const Lock&) = delete;
237 
238     ~Lock() = default;
239 
240     LockType& lock() { return Reference; }
241 
242 protected:
243     constexpr Lock(LockClassId id)
244         : id_{id} {}
245 
246 private:
247     template <typename, typename>
248     friend class Guard;
249     template <size_t, typename, typename>
250     friend class GuardMultiple;
251 
252     LockClassId id() const { return id_.value(); }
253 
254     struct Value {
255         LockClassId value_;
256         LockClassId value() const { return value_; }
257     };
258     struct Dummy {
259         Dummy(LockClassId) {}
260         LockClassId value() const { return kInvalidLockClassId; }
261     };
262 
263     using IdValue = IfLockValidationEnabled<Value, Dummy>;
264 
265     // Stores the lock class id of this lock when validation is enabled.
266     IdValue id_;
267 };
268 
269 // Utility type that captures a LockFlags bitmask in the type system. This may
270 // be used to pass extra LockFlags to the LockDep<> constructor.
271 template <LockFlags Flags = LockFlagsNone>
272 struct ExtraFlags {};
273 
274 // Lock wrapper class that implements lock dependency checks. The template
275 // argument |Class| should be a type that uniquely defines the class, such as
276 // the type of the containing scope. The template argument |LockType| is the
277 // type of the lock to wrap. The template argument |Index| may be used to
278 // differentiate lock classes between multiple locks within the same scope.
279 //
280 // For example:
281 //
282 //  struct MyType {
283 //      LockDep<MyType, Mutex, 0> lock_a;
284 //      LockDep<MyType, Mutex, 1> lock_b;
285 //      // ...
286 //  };
287 //
288 template <typename Class, typename LockType, size_t Index = 0>
289 class LockDep : public Lock<LockType> {
290 public:
291     // Alias that may be used by subclasses to simplify constructor
292     // expressions.
293     using Base = LockDep;
294 
295     // Alias of the lock class that this wrapper represents.
296     template <LockFlags Flags = LockFlagsNone>
297     using LockClass = ConditionalLockClass<Class,
298                                            RemoveGlobalReference<LockType>,
299                                            Index, Flags>;
300 
301     // Constructor that initializes the underlying lock with the additional
302     // arguments.
303     template <typename... Args>
304     constexpr LockDep(Args&&... args)
305         : Lock<LockType>{LockClass<>::Id(), fbl::forward<Args>(args)...} {}
306 
307     // Constructor that accepts additional LockFlags to apply to the lock class
308     // for this lock. The additional arguments are passed to the underlying
309     // lock.
310     template <LockFlags Flags, typename... Args>
311     constexpr LockDep(ExtraFlags<Flags>, Args&&... args)
312         : Lock<LockType>{LockClass<Flags>::Id(), fbl::forward<Args>(args)...} {}
313 };
314 
315 // Singleton version of the lock wrapper above. This type is appropriate for
316 // global locks. This type is used by the macros LOCK_DEP_SINGLETON_LOCK and
317 // LOCK_DEP_SINGLETON_LOCK_WRAPPER to define instrumented global locks.
318 template <typename Class, typename LockType, LockFlags Flags = LockFlagsNone>
319 class SingletonLockDep : public Lock<LockType> {
320 public:
321     // Alias of the lock class that this wrapper represents.
322     using LockClass = ConditionalLockClass<Class,
323                                            RemoveGlobalReference<LockType>,
324                                            0, Flags>;
325 
326     // Returns a pointer to the singleton object.
327     static Class* Get() {
328         // The singleton instance of the global lock.
329         static Class global_lock;
330 
331         return &global_lock;
332     }
333 
334 protected:
335     // Initializes the base Lock<LockType> with lock class id for this lock. The
336     // additional arguments are pass to the underlying lock.
337     template <typename... Args>
338     constexpr SingletonLockDep(Args&&... args)
339         : Lock<LockType>{LockClass::Id(), fbl::forward<Args>(args)...} {}
340 };
341 
342 } // namespace lockdep
343