| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <zircon/compiler.h> |
| |
| #include <fbl/type_info.h> |
| |
| #include <lockdep/common.h> |
| #include <lockdep/global_reference.h> |
| #include <lockdep/lock_class_state.h> |
| #include <lockdep/lock_traits.h> |
| #include <lockdep/thread_lock_state.h> |
| |
| #include <type_traits> |
| #include <utility> |
| |
| namespace lockdep { |
| |
| // Looks up a lock traits type using ADL to perform cross-namespace matching. |
| // This alias works in concert with the macro LOCK_DEP_TRAITS(type, flags) to |
| // find the defined lock traits for a lock, even when defined in a different |
| // namespace. |
| template <typename T> |
| using LookupLockTraits = |
| decltype(LOCK_DEP_GetLockTraits(static_cast<T*>(nullptr))); |
| |
| // Base lock traits type. If a type has not been tagged with the |
| // LOCK_DEP_TRAITS() then this base type provides the default flags for the lock |
| // type. |
| template <typename T, typename = void> |
| struct LockTraits { |
| static constexpr LockFlags Flags = LockFlagsNone; |
| }; |
| // Returns the flags for a lock type when the type is tagged with |
| // LOCK_DEP_TRAITS(type, flags). |
| template <typename T> |
| struct LockTraits<T, std::void_t<LookupLockTraits<T>>> { |
| static constexpr LockFlags Flags = LookupLockTraits<T>::Flags; |
| }; |
| |
| // Singleton type that represents a lock class. Each template instantiation |
| // represents an independent, unique lock class. This type maintains a global |
| // dependency set that tracks which other lock classes have been observed |
| // being held prior to acquisitions of this lock class. This type is only used |
| // when lock validation is enabled, otherwise DummyLockClass takes its place. |
| template <typename Class, typename LockType, size_t Index, LockFlags Flags> |
| class LockClass { |
| public: |
| // Returns the unique lock class id for this lock class. |
| static LockClassId Id() { |
| return lock_class_state_.id(); |
| } |
| |
| // Returns the LockClassState instance for this lock class. |
| static LockClassState* GetLockClassState() { return &lock_class_state_; } |
| |
| private: |
| LockClass() = default; |
| ~LockClass() = default; |
| LockClass(const LockClass&) = delete; |
| void operator=(const LockClass&) = delete; |
| |
| // Returns the name of this lock class. |
| constexpr static const char* GetName() { |
| return fbl::TypeInfo<LockClass>::Name(); |
| } |
| |
| // Lock free dependency set that tracks which lock classes have been observed |
| // being held prior to acquisitions of this lock class. |
| static LockDependencySet dependency_set_; |
| |
| // This static member serves a dual role: |
| // 1. Stores the id, name, and pointer to dependency set for this lock class. |
| // 2. The address of this member serves as the unique id for this lock class. |
| static LockClassState lock_class_state_; |
| }; |
| |
| // Initializes the value of the lock class state with the id, typeid name, and |
| // dependency set of the lock class. This results in a global initializer that |
| // performs trivial assignment. |
| template <typename Class, typename LockType, size_t Index, LockFlags Flags> |
| LockClassState LockClass<Class, LockType, Index, Flags>::lock_class_state_ = { |
| LockClass<Class, LockType, Index, Flags>::GetName(), |
| &LockClass<Class, LockType, Index, Flags>::dependency_set_, |
| static_cast<LockFlags>(LockTraits<LockType>::Flags | Flags)}; |
| |
| // The storage for this static member is allocated as zeroed memory. |
| template <typename Class, typename LockType, size_t Index, LockFlags Flags> |
| LockDependencySet LockClass<Class, LockType, Index, Flags>::dependency_set_; |
| |
| // Dummy type used in place of LockClass when validation is disabled. This type |
| // does not create static dependency tracking structures that LockClass does. |
| struct DummyLockClass { |
| static LockClassId Id() { return kInvalidLockClassId; } |
| }; |
| |
| // Alias that selects LockClass<Class, LockType, Index, Flags> when validation |
| // is enabled or DummyLockClass when validation is disabled. |
| template <typename Class, typename LockType, size_t Index, LockFlags Flags> |
| using ConditionalLockClass = IfLockValidationEnabled< |
| LockClass<Class, LockType, Index, Flags>, DummyLockClass>; |
| |
| // Base lock wrapper type that provides the essential interface required by |
| // Guard<LockType, Option> to perform locking and validation. This type wraps |
| // an instance of LockType that is used to perform the actual synchronization. |
| // When lock validation is enabled this type also stores the LockClassId for |
| // the lock class this lock belongs to. |
| // |
| // The "lock class" that each lock belongs to is created by each unique |
| // instantiation of the types LockDep<Class, LockType, Index> or |
| // SingletonLockDep<Class, LockType, LockFlags> below. These types subclass |
| // Lock<LockType> to provide type erasure required when virtual accessors are |
| // used to specify capabilities to Clang static lock analysis. |
| // |
| // For example, the lock_ members of LockableType and AnotherLockableType below |
| // are different types due to how LockDep<> instruments the lock members. |
| // Both unique LockDep<> instantiations derive from the same Lock<LockType>, |
| // providing a common capability type (erasing the LockDep<> type) that may be |
| // used in static lock annotations with the expression "get_lock()". |
| // |
| // struct LockableInterface { |
| // virtual ~LockableInterface = 0; |
| // virtual Lock<fbl::Mutex>* get_lock() = 0; |
| // virtual void Clear() __TA_REQUIRES(get_lock()) = 0; |
| // }; |
| // |
| // class LockableType : public LockableInterface { |
| // public: |
| // LockableType() = default; |
| // ~LockableType() override = default; |
| // |
| // Lock<fbl::Mutex>* get_lock() override { return &lock_; } |
| // |
| // void Clear() override { count_ = 0; } |
| // |
| // void Increment() { |
| // Guard<fbl::Mutex> guard{get_lock()}; |
| // count_++; |
| // } |
| // |
| // |
| // private: |
| // LOCK_DEP_INSTRUMENT(LockableType, fbl::Mutex) lock_; |
| // int count_ __TA_GUARDED(get_lock()) {0}; |
| // }; |
| // |
| // class AnotherLockableType : public LockableInterface { |
| // public: |
| // AnotherLockableType() = default; |
| // ~AnotherLockableType() override = default; |
| // |
| // Lock<fbl::Mutex>* get_lock() override { return &lock_; } |
| // |
| // void Clear() override { test_.clear(); } |
| // |
| // void Append(const std::string& string) { |
| // Guard<fbl::Mutex> guard{get_lock()}; |
| // text_.append(string) |
| // } |
| // |
| // |
| // private: |
| // LOCK_DEP_INSTRUMENT(AnotherLockableType, fbl::Mutex) lock_; |
| // std::string text_ __TA_GUARDED(get_lock()) {}; |
| // }; |
| // |
| template <typename LockType> |
| class __TA_CAPABILITY("mutex") Lock { |
| public: |
| Lock(Lock&&) = delete; |
| Lock(const Lock&) = delete; |
| Lock& operator=(Lock&&) = delete; |
| Lock& operator=(const Lock&) = delete; |
| |
| ~Lock() = default; |
| |
| // Provides direct access to the underlying lock. Care should be taken when |
| // manipulating the underlying lock. Incorrect manipulation could confuse |
| // the validator, trigger lock assertions, and/or deadlock. |
| LockType& lock() { return lock_; } |
| |
| // Returns the capability of the underlying lock. This is expected by Guard |
| // as an additional static assertion target. |
| LockType& capability() __TA_RETURN_CAPABILITY(lock_) { return lock_; } |
| |
| protected: |
| // Initializes the Lock instance with the given LockClassId and passes any |
| // additional arguments to the underlying lock constructor. |
| template <typename... Args> |
| constexpr Lock(LockClassId id, Args&&... args) |
| : id_{id}, lock_(std::forward<Args>(args)...) {} |
| |
| private: |
| template <typename, typename, typename> |
| friend class Guard; |
| template <size_t, typename, typename> |
| friend class GuardMultiple; |
| |
| // Returns the LockClassId of the lock class this lock belongs to. |
| LockClassId id() const { return id_.value(); } |
| |
| // Value type that stores the LockClassId for this lock when validation is |
| // enabled. |
| struct Value { |
| LockClassId value_; |
| LockClassId value() const { return value_; } |
| }; |
| |
| // Dummy type that stores nothing when validation is disabled. |
| struct Dummy { |
| Dummy(LockClassId) {} |
| LockClassId value() const { return kInvalidLockClassId; } |
| }; |
| |
| // Selects between Value or Dummy based on whether validation is enabled. |
| using IdValue = IfLockValidationEnabled<Value, Dummy>; |
| |
| // Stores the lock class id of this lock when validation is enabled. |
| IdValue id_; |
| |
| // The underlying lock managed by this dependency tracking wrapper. |
| LockType lock_; |
| }; |
| |
| // Specialization of Lock<LockType> that wraps a static/global raw lock. This |
| // type permits creating a tracked alias of a raw lock of type LockType that |
| // has static storage duration, with either external or internal linkage. |
| // |
| // This type supports transitioning from C-compatible APIs to full C++. |
| template <typename LockType, LockType& Reference> |
| class __TA_CAPABILITY("mutex") Lock<GlobalReference<LockType, Reference>> { |
| public: |
| Lock(Lock&&) = delete; |
| Lock(const Lock&) = delete; |
| Lock& operator=(Lock&&) = delete; |
| Lock& operator=(const Lock&) = delete; |
| |
| ~Lock() = default; |
| |
| LockType& lock() { return Reference; } |
| |
| protected: |
| constexpr Lock(LockClassId id) |
| : id_{id} {} |
| |
| private: |
| template <typename, typename, typename> |
| friend class Guard; |
| template <size_t, typename, typename> |
| friend class GuardMultiple; |
| |
| LockClassId id() const { return id_.value(); } |
| |
| struct Value { |
| LockClassId value_; |
| LockClassId value() const { return value_; } |
| }; |
| struct Dummy { |
| Dummy(LockClassId) {} |
| LockClassId value() const { return kInvalidLockClassId; } |
| }; |
| |
| using IdValue = IfLockValidationEnabled<Value, Dummy>; |
| |
| // Stores the lock class id of this lock when validation is enabled. |
| IdValue id_; |
| }; |
| |
| // Utility type that captures a LockFlags bitmask in the type system. This may |
| // be used to pass extra LockFlags to the LockDep<> constructor. |
| template <LockFlags Flags = LockFlagsNone> |
| struct ExtraFlags {}; |
| |
| // Lock wrapper class that implements lock dependency checks. The template |
| // argument |Class| should be a type that uniquely defines the class, such as |
| // the type of the containing scope. The template argument |LockType| is the |
| // type of the lock to wrap. The template argument |Index| may be used to |
| // differentiate lock classes between multiple locks within the same scope. |
| // |
| // For example: |
| // |
| // struct MyType { |
| // LockDep<MyType, Mutex, 0> lock_a; |
| // LockDep<MyType, Mutex, 1> lock_b; |
| // // ... |
| // }; |
| // |
| template <typename Class, typename LockType, size_t Index = 0> |
| class LockDep : public Lock<LockType> { |
| public: |
| // Alias that may be used by subclasses to simplify constructor |
| // expressions. |
| using Base = LockDep; |
| |
| // Alias of the lock class that this wrapper represents. |
| template <LockFlags Flags = LockFlagsNone> |
| using LockClass = ConditionalLockClass<Class, |
| RemoveGlobalReference<LockType>, |
| Index, Flags>; |
| |
| // Constructor that initializes the underlying lock with the additional |
| // arguments. |
| template <typename... Args> |
| constexpr LockDep(Args&&... args) |
| : Lock<LockType>{LockClass<>::Id(), std::forward<Args>(args)...} {} |
| |
| // Constructor that accepts additional LockFlags to apply to the lock class |
| // for this lock. The additional arguments are passed to the underlying |
| // lock. |
| template <LockFlags Flags, typename... Args> |
| constexpr LockDep(ExtraFlags<Flags>, Args&&... args) |
| : Lock<LockType>{LockClass<Flags>::Id(), std::forward<Args>(args)...} {} |
| }; |
| |
| // Singleton version of the lock wrapper above. This type is appropriate for |
| // global locks. This type is used by the macros LOCK_DEP_SINGLETON_LOCK and |
| // LOCK_DEP_SINGLETON_LOCK_WRAPPER to define instrumented global locks. |
| template <typename Class, typename LockType, LockFlags Flags = LockFlagsNone> |
| class SingletonLockDep : public Lock<LockType> { |
| public: |
| // Alias of the lock class that this wrapper represents. |
| using LockClass = ConditionalLockClass<Class, |
| RemoveGlobalReference<LockType>, |
| 0, Flags>; |
| |
| // Returns a pointer to the singleton object. |
| static Class* Get() { |
| // The singleton instance of the global lock. |
| static Class global_lock; |
| |
| return &global_lock; |
| } |
| |
| protected: |
| // Initializes the base Lock<LockType> with lock class id for this lock. The |
| // additional arguments are pass to the underlying lock. |
| template <typename... Args> |
| constexpr SingletonLockDep(Args&&... args) |
| : Lock<LockType>{LockClass::Id(), std::forward<Args>(args)...} {} |
| }; |
| |
| } // namespace lockdep |