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