diff options
author | Andreas Kling <kling@serenityos.org> | 2022-08-19 20:53:40 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-08-20 17:20:43 +0200 |
commit | 11eee67b8510767d76fb4793e3b62ac1793dd723 (patch) | |
tree | 8ce47a3813ce74bba56c60f62b29bdd6cdf287da /Kernel/Library | |
parent | e475263113387404e63cdc3666391934604eb6e7 (diff) | |
download | serenity-11eee67b8510767d76fb4793e3b62ac1793dd723.zip |
Kernel: Make self-contained locking smart pointers their own classes
Until now, our kernel has reimplemented a number of AK classes to
provide automatic internal locking:
- RefPtr
- NonnullRefPtr
- WeakPtr
- Weakable
This patch renames the Kernel classes so that they can coexist with
the original AK classes:
- RefPtr => LockRefPtr
- NonnullRefPtr => NonnullLockRefPtr
- WeakPtr => LockWeakPtr
- Weakable => LockWeakable
The goal here is to eventually get rid of the Lock* classes in favor of
using external locking.
Diffstat (limited to 'Kernel/Library')
-rw-r--r-- | Kernel/Library/LockRefPtr.h (renamed from Kernel/Library/ThreadSafeRefPtr.h) | 142 | ||||
-rw-r--r-- | Kernel/Library/LockWeakPtr.h (renamed from Kernel/Library/ThreadSafeWeakPtr.h) | 70 | ||||
-rw-r--r-- | Kernel/Library/LockWeakable.h (renamed from Kernel/Library/ThreadSafeWeakable.h) | 30 | ||||
-rw-r--r-- | Kernel/Library/NonnullLockRefPtr.h (renamed from Kernel/Library/ThreadSafeNonnullRefPtr.h) | 111 | ||||
-rw-r--r-- | Kernel/Library/NonnullLockRefPtrVector.h | 21 |
5 files changed, 191 insertions, 183 deletions
diff --git a/Kernel/Library/ThreadSafeRefPtr.h b/Kernel/Library/LockRefPtr.h index b1e341d7e9..90f5889a8d 100644 --- a/Kernel/Library/ThreadSafeRefPtr.h +++ b/Kernel/Library/LockRefPtr.h @@ -10,16 +10,16 @@ #include <AK/Atomic.h> #include <AK/Error.h> #include <AK/Format.h> -#include <AK/NonnullRefPtr.h> #include <AK/StdLibExtras.h> #include <AK/Traits.h> #include <AK/Types.h> +#include <Kernel/Library/NonnullLockRefPtr.h> #ifdef KERNEL # include <Kernel/Arch/Processor.h> # include <Kernel/Arch/ScopedCritical.h> #endif -#define THREADSAFEREFPTR_SCRUB_BYTE 0xa0 +#define LOCKREFPTR_SCRUB_BYTE 0xa0 namespace AK { @@ -27,7 +27,7 @@ template<typename T> class OwnPtr; template<typename T> -struct RefPtrTraits { +struct LockRefPtrTraits { ALWAYS_INLINE static T* as_ptr(FlatPtr bits) { return (T*)(bits & ~(FlatPtr)1); @@ -88,7 +88,7 @@ struct RefPtrTraits { ALWAYS_INLINE static FlatPtr lock(Atomic<FlatPtr>& atomic_var) { // This sets the lock bit atomically, preventing further modifications. - // This is important when e.g. copying a RefPtr where the source + // This is important when e.g. copying a LockRefPtr where the source // might be released and freed too quickly. This allows us // to temporarily lock the pointer so we can add a reference, then // unlock it @@ -117,24 +117,24 @@ struct RefPtrTraits { }; template<typename T, typename PtrTraits> -class [[nodiscard]] RefPtr { +class [[nodiscard]] LockRefPtr { template<typename U, typename P> - friend class RefPtr; + friend class LockRefPtr; template<typename U> - friend class WeakPtr; + friend class LockWeakPtr; public: enum AdoptTag { Adopt }; - RefPtr() = default; - RefPtr(const T* ptr) + LockRefPtr() = default; + LockRefPtr(const T* ptr) : m_bits(PtrTraits::as_bits(const_cast<T*>(ptr))) { ref_if_not_null(const_cast<T*>(ptr)); } - RefPtr(const T& object) + LockRefPtr(const T& object) : m_bits(PtrTraits::as_bits(const_cast<T*>(&object))) { T* ptr = const_cast<T*>(&object); @@ -142,58 +142,58 @@ public: VERIFY(!is_null()); ptr->ref(); } - RefPtr(AdoptTag, T& object) + LockRefPtr(AdoptTag, T& object) : m_bits(PtrTraits::as_bits(&object)) { VERIFY(!is_null()); } - RefPtr(RefPtr&& other) + LockRefPtr(LockRefPtr&& other) : m_bits(other.leak_ref_raw()) { } - ALWAYS_INLINE RefPtr(NonnullRefPtr<T> const& other) + ALWAYS_INLINE LockRefPtr(NonnullLockRefPtr<T> const& other) : m_bits(PtrTraits::as_bits(const_cast<T*>(other.add_ref()))) { } template<typename U> - ALWAYS_INLINE RefPtr(NonnullRefPtr<U> const& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE LockRefPtr(NonnullLockRefPtr<U> const& other) requires(IsConvertible<U*, T*>) : m_bits(PtrTraits::as_bits(const_cast<U*>(other.add_ref()))) { } template<typename U> - ALWAYS_INLINE RefPtr(NonnullRefPtr<U>&& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE LockRefPtr(NonnullLockRefPtr<U>&& other) requires(IsConvertible<U*, T*>) : m_bits(PtrTraits::as_bits(&other.leak_ref())) { VERIFY(!is_null()); } - template<typename U, typename P = RefPtrTraits<U>> - RefPtr(RefPtr<U, P>&& other) requires(IsConvertible<U*, T*>) + template<typename U, typename P = LockRefPtrTraits<U>> + LockRefPtr(LockRefPtr<U, P>&& other) requires(IsConvertible<U*, T*>) : m_bits(PtrTraits::template convert_from<U, P>(other.leak_ref_raw())) { } - RefPtr(RefPtr const& other) + LockRefPtr(LockRefPtr const& other) : m_bits(other.add_ref_raw()) { } - template<typename U, typename P = RefPtrTraits<U>> - RefPtr(RefPtr<U, P> const& other) requires(IsConvertible<U*, T*>) + template<typename U, typename P = LockRefPtrTraits<U>> + LockRefPtr(LockRefPtr<U, P> const& other) requires(IsConvertible<U*, T*>) : m_bits(other.add_ref_raw()) { } - ALWAYS_INLINE ~RefPtr() + ALWAYS_INLINE ~LockRefPtr() { clear(); #ifdef SANITIZE_PTRS - m_bits.store(explode_byte(THREADSAFEREFPTR_SCRUB_BYTE), AK::MemoryOrder::memory_order_relaxed); + m_bits.store(explode_byte(LOCKREFPTR_SCRUB_BYTE), AK::MemoryOrder::memory_order_relaxed); #endif } template<typename U> - RefPtr(OwnPtr<U> const&) = delete; + LockRefPtr(OwnPtr<U> const&) = delete; template<typename U> - RefPtr& operator=(OwnPtr<U> const&) = delete; + LockRefPtr& operator=(OwnPtr<U> const&) = delete; - void swap(RefPtr& other) + void swap(LockRefPtr& other) { if (this == &other) return; @@ -204,8 +204,8 @@ public: PtrTraits::exchange(other.m_bits, bits); } - template<typename U, typename P = RefPtrTraits<U>> - void swap(RefPtr<U, P>& other) requires(IsConvertible<U*, T*>) + template<typename U, typename P = LockRefPtrTraits<U>> + void swap(LockRefPtr<U, P>& other) requires(IsConvertible<U*, T*>) { // NOTE: swap is not atomic! FlatPtr other_bits = P::exchange(other.m_bits, P::default_null_value); @@ -213,41 +213,41 @@ public: P::exchange(other.m_bits, P::template convert_from<U, P>(bits)); } - ALWAYS_INLINE RefPtr& operator=(RefPtr&& other) + ALWAYS_INLINE LockRefPtr& operator=(LockRefPtr&& other) { if (this != &other) assign_raw(other.leak_ref_raw()); return *this; } - template<typename U, typename P = RefPtrTraits<U>> - ALWAYS_INLINE RefPtr& operator=(RefPtr<U, P>&& other) requires(IsConvertible<U*, T*>) + template<typename U, typename P = LockRefPtrTraits<U>> + ALWAYS_INLINE LockRefPtr& operator=(LockRefPtr<U, P>&& other) requires(IsConvertible<U*, T*>) { assign_raw(PtrTraits::template convert_from<U, P>(other.leak_ref_raw())); return *this; } template<typename U> - ALWAYS_INLINE RefPtr& operator=(NonnullRefPtr<U>&& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE LockRefPtr& operator=(NonnullLockRefPtr<U>&& other) requires(IsConvertible<U*, T*>) { assign_raw(PtrTraits::as_bits(&other.leak_ref())); return *this; } - ALWAYS_INLINE RefPtr& operator=(NonnullRefPtr<T> const& other) + ALWAYS_INLINE LockRefPtr& operator=(NonnullLockRefPtr<T> const& other) { assign_raw(PtrTraits::as_bits(other.add_ref())); return *this; } template<typename U> - ALWAYS_INLINE RefPtr& operator=(NonnullRefPtr<U> const& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE LockRefPtr& operator=(NonnullLockRefPtr<U> const& other) requires(IsConvertible<U*, T*>) { assign_raw(PtrTraits::as_bits(other.add_ref())); return *this; } - ALWAYS_INLINE RefPtr& operator=(RefPtr const& other) + ALWAYS_INLINE LockRefPtr& operator=(LockRefPtr const& other) { if (this != &other) assign_raw(other.add_ref_raw()); @@ -255,41 +255,41 @@ public: } template<typename U> - ALWAYS_INLINE RefPtr& operator=(RefPtr<U> const& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE LockRefPtr& operator=(LockRefPtr<U> const& other) requires(IsConvertible<U*, T*>) { assign_raw(other.add_ref_raw()); return *this; } - ALWAYS_INLINE RefPtr& operator=(const T* ptr) + ALWAYS_INLINE LockRefPtr& operator=(const T* ptr) { ref_if_not_null(const_cast<T*>(ptr)); assign_raw(PtrTraits::as_bits(const_cast<T*>(ptr))); return *this; } - ALWAYS_INLINE RefPtr& operator=(const T& object) + ALWAYS_INLINE LockRefPtr& operator=(const T& object) { const_cast<T&>(object).ref(); assign_raw(PtrTraits::as_bits(const_cast<T*>(&object))); return *this; } - RefPtr& operator=(std::nullptr_t) + LockRefPtr& operator=(std::nullptr_t) { clear(); return *this; } - ALWAYS_INLINE bool assign_if_null(RefPtr&& other) + ALWAYS_INLINE bool assign_if_null(LockRefPtr&& other) { if (this == &other) return is_null(); return PtrTraits::exchange_if_null(m_bits, other.leak_ref_raw()); } - template<typename U, typename P = RefPtrTraits<U>> - ALWAYS_INLINE bool assign_if_null(RefPtr<U, P>&& other) + template<typename U, typename P = LockRefPtrTraits<U>> + ALWAYS_INLINE bool assign_if_null(LockRefPtr<U, P>&& other) { if (this == &other) return is_null(); @@ -309,11 +309,11 @@ public: return PtrTraits::as_ptr(bits); } - NonnullRefPtr<T> release_nonnull() + NonnullLockRefPtr<T> release_nonnull() { FlatPtr bits = PtrTraits::exchange(m_bits, PtrTraits::default_null_value); VERIFY(!PtrTraits::is_null(bits)); - return NonnullRefPtr<T>(NonnullRefPtr<T>::Adopt, *PtrTraits::as_ptr(bits)); + return NonnullLockRefPtr<T>(NonnullLockRefPtr<T>::Adopt, *PtrTraits::as_ptr(bits)); } ALWAYS_INLINE T* ptr() { return as_ptr(); } @@ -347,11 +347,11 @@ public: bool operator==(std::nullptr_t) const { return is_null(); } bool operator!=(std::nullptr_t) const { return !is_null(); } - bool operator==(RefPtr const& other) const { return as_ptr() == other.as_ptr(); } - bool operator!=(RefPtr const& other) const { return as_ptr() != other.as_ptr(); } + bool operator==(LockRefPtr const& other) const { return as_ptr() == other.as_ptr(); } + bool operator!=(LockRefPtr const& other) const { return as_ptr() != other.as_ptr(); } - bool operator==(RefPtr& other) { return as_ptr() == other.as_ptr(); } - bool operator!=(RefPtr& other) { return as_ptr() != other.as_ptr(); } + bool operator==(LockRefPtr& other) { return as_ptr() == other.as_ptr(); } + bool operator!=(LockRefPtr& other) { return as_ptr() != other.as_ptr(); } bool operator==(const T* other) const { return as_ptr() == other; } bool operator!=(const T* other) const { return as_ptr() != other; } @@ -405,7 +405,7 @@ private: Kernel::ScopedCritical critical; #endif // This prevents a race condition between thread A and B: - // 1. Thread A copies RefPtr, e.g. through assignment or copy constructor, + // 1. Thread A copies LockRefPtr, e.g. through assignment or copy constructor, // gets the pointer from source, but is pre-empted before adding // another reference // 2. Thread B calls clear, leak_ref, or release_nonnull on source, and @@ -445,64 +445,64 @@ private: }; template<typename T> -struct Formatter<RefPtr<T>> : Formatter<const T*> { - ErrorOr<void> format(FormatBuilder& builder, RefPtr<T> const& value) +struct Formatter<LockRefPtr<T>> : Formatter<const T*> { + ErrorOr<void> format(FormatBuilder& builder, LockRefPtr<T> const& value) { return Formatter<const T*>::format(builder, value.ptr()); } }; template<typename T> -struct Traits<RefPtr<T>> : public GenericTraits<RefPtr<T>> { +struct Traits<LockRefPtr<T>> : public GenericTraits<LockRefPtr<T>> { using PeekType = T*; using ConstPeekType = const T*; - static unsigned hash(RefPtr<T> const& p) { return ptr_hash(p.ptr()); } - static bool equals(RefPtr<T> const& a, RefPtr<T> const& b) { return a.ptr() == b.ptr(); } + static unsigned hash(LockRefPtr<T> const& p) { return ptr_hash(p.ptr()); } + static bool equals(LockRefPtr<T> const& a, LockRefPtr<T> const& b) { return a.ptr() == b.ptr(); } }; template<typename T, typename U> -inline NonnullRefPtr<T> static_ptr_cast(NonnullRefPtr<U> const& ptr) +inline NonnullLockRefPtr<T> static_ptr_cast(NonnullLockRefPtr<U> const& ptr) { - return NonnullRefPtr<T>(static_cast<const T&>(*ptr)); + return NonnullLockRefPtr<T>(static_cast<const T&>(*ptr)); } -template<typename T, typename U, typename PtrTraits = RefPtrTraits<T>> -inline RefPtr<T> static_ptr_cast(RefPtr<U> const& ptr) +template<typename T, typename U, typename PtrTraits = LockRefPtrTraits<T>> +inline LockRefPtr<T> static_ptr_cast(LockRefPtr<U> const& ptr) { - return RefPtr<T, PtrTraits>(static_cast<const T*>(ptr.ptr())); + return LockRefPtr<T, PtrTraits>(static_cast<const T*>(ptr.ptr())); } template<typename T, typename PtrTraitsT, typename U, typename PtrTraitsU> -inline void swap(RefPtr<T, PtrTraitsT>& a, RefPtr<U, PtrTraitsU>& b) requires(IsConvertible<U*, T*>) +inline void swap(LockRefPtr<T, PtrTraitsT>& a, LockRefPtr<U, PtrTraitsU>& b) requires(IsConvertible<U*, T*>) { a.swap(b); } template<typename T> -inline RefPtr<T> adopt_ref_if_nonnull(T* object) +inline LockRefPtr<T> adopt_lock_ref_if_nonnull(T* object) { if (object) - return RefPtr<T>(RefPtr<T>::Adopt, *object); + return LockRefPtr<T>(LockRefPtr<T>::Adopt, *object); return {}; } template<typename T, class... Args> -requires(IsConstructible<T, Args...>) inline ErrorOr<NonnullRefPtr<T>> try_make_ref_counted(Args&&... args) +requires(IsConstructible<T, Args...>) inline ErrorOr<NonnullLockRefPtr<T>> try_make_lock_ref_counted(Args&&... args) { - return adopt_nonnull_ref_or_enomem(new (nothrow) T(forward<Args>(args)...)); + return adopt_nonnull_lock_ref_or_enomem(new (nothrow) T(forward<Args>(args)...)); } // FIXME: Remove once P0960R3 is available in Clang. template<typename T, class... Args> -inline ErrorOr<NonnullRefPtr<T>> try_make_ref_counted(Args&&... args) +inline ErrorOr<NonnullLockRefPtr<T>> try_make_lock_ref_counted(Args&&... args) { - return adopt_nonnull_ref_or_enomem(new (nothrow) T { forward<Args>(args)... }); + return adopt_nonnull_lock_ref_or_enomem(new (nothrow) T { forward<Args>(args)... }); } template<typename T> -inline ErrorOr<NonnullRefPtr<T>> adopt_nonnull_ref_or_enomem(T* object) +inline ErrorOr<NonnullLockRefPtr<T>> adopt_nonnull_lock_ref_or_enomem(T* object) { - auto result = adopt_ref_if_nonnull(object); + auto result = adopt_lock_ref_if_nonnull(object); if (!result) return Error::from_errno(ENOMEM); return result.release_nonnull(); @@ -510,11 +510,11 @@ inline ErrorOr<NonnullRefPtr<T>> adopt_nonnull_ref_or_enomem(T* object) } -using AK::adopt_ref_if_nonnull; -using AK::RefPtr; +using AK::adopt_lock_ref_if_nonnull; +using AK::LockRefPtr; using AK::static_ptr_cast; -using AK::try_make_ref_counted; +using AK::try_make_lock_ref_counted; #ifdef KERNEL -using AK::adopt_nonnull_ref_or_enomem; +using AK::adopt_nonnull_lock_ref_or_enomem; #endif diff --git a/Kernel/Library/ThreadSafeWeakPtr.h b/Kernel/Library/LockWeakPtr.h index c50bab3651..3b63864ce2 100644 --- a/Kernel/Library/ThreadSafeWeakPtr.h +++ b/Kernel/Library/LockWeakPtr.h @@ -6,66 +6,66 @@ #pragma once -#include <AK/Weakable.h> +#include <Kernel/Library/LockWeakable.h> namespace AK { template<typename T> -class [[nodiscard]] WeakPtr { +class [[nodiscard]] LockWeakPtr { template<typename U> - friend class Weakable; + friend class LockWeakable; public: - WeakPtr() = default; + LockWeakPtr() = default; template<typename U> - WeakPtr(WeakPtr<U> const& other) requires(IsBaseOf<T, U>) + LockWeakPtr(WeakPtr<U> const& other) requires(IsBaseOf<T, U>) : m_link(other.m_link) { } template<typename U> - WeakPtr(WeakPtr<U>&& other) requires(IsBaseOf<T, U>) + LockWeakPtr(WeakPtr<U>&& other) requires(IsBaseOf<T, U>) : m_link(other.take_link()) { } template<typename U> - WeakPtr& operator=(WeakPtr<U>&& other) requires(IsBaseOf<T, U>) + LockWeakPtr& operator=(WeakPtr<U>&& other) requires(IsBaseOf<T, U>) { m_link = other.take_link(); return *this; } template<typename U> - WeakPtr& operator=(WeakPtr<U> const& other) requires(IsBaseOf<T, U>) + LockWeakPtr& operator=(WeakPtr<U> const& other) requires(IsBaseOf<T, U>) { if ((void const*)this != (void const*)&other) m_link = other.m_link; return *this; } - WeakPtr& operator=(std::nullptr_t) + LockWeakPtr& operator=(std::nullptr_t) { clear(); return *this; } template<typename U> - WeakPtr(const U& object) requires(IsBaseOf<T, U>) + LockWeakPtr(const U& object) requires(IsBaseOf<T, U>) : m_link(object.template try_make_weak_ptr<U>().release_value_but_fixme_should_propagate_errors().take_link()) { } template<typename U> - WeakPtr(const U* object) requires(IsBaseOf<T, U>) + LockWeakPtr(const U* object) requires(IsBaseOf<T, U>) { if (object) m_link = object->template try_make_weak_ptr<U>().release_value_but_fixme_should_propagate_errors().take_link(); } template<typename U> - WeakPtr(RefPtr<U> const& object) requires(IsBaseOf<T, U>) + LockWeakPtr(LockRefPtr<U> const& object) requires(IsBaseOf<T, U>) { object.do_while_locked([&](U* obj) { if (obj) @@ -74,7 +74,7 @@ public: } template<typename U> - WeakPtr(NonnullRefPtr<U> const& object) requires(IsBaseOf<T, U>) + LockWeakPtr(NonnullLockRefPtr<U> const& object) requires(IsBaseOf<T, U>) { object.do_while_locked([&](U* obj) { if (obj) @@ -83,14 +83,14 @@ public: } template<typename U> - WeakPtr& operator=(const U& object) requires(IsBaseOf<T, U>) + LockWeakPtr& operator=(const U& object) requires(IsBaseOf<T, U>) { m_link = object.template try_make_weak_ptr<U>().release_value_but_fixme_should_propagate_errors().take_link(); return *this; } template<typename U> - WeakPtr& operator=(const U* object) requires(IsBaseOf<T, U>) + LockWeakPtr& operator=(const U* object) requires(IsBaseOf<T, U>) { if (object) m_link = object->template try_make_weak_ptr<U>().release_value_but_fixme_should_propagate_errors().take_link(); @@ -100,7 +100,7 @@ public: } template<typename U> - WeakPtr& operator=(RefPtr<U> const& object) requires(IsBaseOf<T, U>) + LockWeakPtr& operator=(LockRefPtr<U> const& object) requires(IsBaseOf<T, U>) { object.do_while_locked([&](U* obj) { if (obj) @@ -112,7 +112,7 @@ public: } template<typename U> - WeakPtr& operator=(NonnullRefPtr<U> const& object) requires(IsBaseOf<T, U>) + LockWeakPtr& operator=(NonnullLockRefPtr<U> const& object) requires(IsBaseOf<T, U>) { object.do_while_locked([&](U* obj) { if (obj) @@ -123,13 +123,13 @@ public: return *this; } - [[nodiscard]] RefPtr<T> strong_ref() const + [[nodiscard]] LockRefPtr<T> strong_ref() const { // This only works with RefCounted objects, but it is the only - // safe way to get a strong reference from a WeakPtr. Any code + // safe way to get a strong reference from a LockWeakPtr. Any code // that uses objects not derived from RefCounted will have to // use unsafe_ptr(), but as the name suggests, it is not safe... - RefPtr<T> ref; + LockRefPtr<T> ref; // Using do_while_locked protects against a race with clear()! m_link.do_while_locked([&](WeakLink* link) { if (link) @@ -153,20 +153,20 @@ public: [[nodiscard]] bool is_null() const { return !m_link || m_link->is_null(); } void clear() { m_link = nullptr; } - [[nodiscard]] RefPtr<WeakLink> take_link() { return move(m_link); } + [[nodiscard]] LockRefPtr<WeakLink> take_link() { return move(m_link); } private: - WeakPtr(RefPtr<WeakLink> const& link) + LockWeakPtr(LockRefPtr<WeakLink> const& link) : m_link(link) { } - RefPtr<WeakLink> m_link; + LockRefPtr<WeakLink> m_link; }; template<typename T> template<typename U> -inline ErrorOr<WeakPtr<U>> Weakable<T>::try_make_weak_ptr() const +inline ErrorOr<LockWeakPtr<U>> LockWeakable<T>::try_make_weak_ptr() const { if constexpr (IsBaseOf<AtomicRefCountedBase, T>) { // Checking m_being_destroyed isn't sufficient when dealing with @@ -176,21 +176,21 @@ inline ErrorOr<WeakPtr<U>> Weakable<T>::try_make_weak_ptr() const // that we prevent the destructor and revoke_weak_ptrs from being // triggered until we're done. if (!static_cast<const T*>(this)->try_ref()) - return WeakPtr<U> {}; + return LockWeakPtr<U> {}; } else { // For non-RefCounted types this means a weak reference can be - // obtained until the ~Weakable destructor is invoked! + // obtained until the ~LockWeakable destructor is invoked! if (m_being_destroyed.load(AK::MemoryOrder::memory_order_acquire)) - return WeakPtr<U> {}; + return LockWeakPtr<U> {}; } if (!m_link) { // There is a small chance that we create a new WeakLink and throw // it away because another thread beat us to it. But the window is // pretty small and the overhead isn't terrible. - m_link.assign_if_null(TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WeakLink(const_cast<T&>(static_cast<const T&>(*this)))))); + m_link.assign_if_null(TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) WeakLink(const_cast<T&>(static_cast<const T&>(*this)))))); } - WeakPtr<U> weak_ptr(m_link); + LockWeakPtr<U> weak_ptr(m_link); if constexpr (IsBaseOf<AtomicRefCountedBase, T>) { // Now drop the reference we temporarily added @@ -198,15 +198,15 @@ inline ErrorOr<WeakPtr<U>> Weakable<T>::try_make_weak_ptr() const // We just dropped the last reference, which should have called // revoke_weak_ptrs, which should have invalidated our weak_ptr VERIFY(!weak_ptr.strong_ref()); - return WeakPtr<U> {}; + return LockWeakPtr<U> {}; } } return weak_ptr; } template<typename T> -struct Formatter<WeakPtr<T>> : Formatter<const T*> { - ErrorOr<void> format(FormatBuilder& builder, WeakPtr<T> const& value) +struct Formatter<LockWeakPtr<T>> : Formatter<const T*> { + ErrorOr<void> format(FormatBuilder& builder, LockWeakPtr<T> const& value) { auto ref = value.strong_ref(); return Formatter<const T*>::format(builder, ref.ptr()); @@ -214,14 +214,14 @@ struct Formatter<WeakPtr<T>> : Formatter<const T*> { }; template<typename T> -ErrorOr<WeakPtr<T>> try_make_weak_ptr_if_nonnull(T const* ptr) +ErrorOr<LockWeakPtr<T>> try_make_weak_ptr_if_nonnull(T const* ptr) { if (ptr) { return ptr->template try_make_weak_ptr<T>(); } - return WeakPtr<T> {}; + return LockWeakPtr<T> {}; } } -using AK::WeakPtr; +using AK::LockWeakPtr; diff --git a/Kernel/Library/ThreadSafeWeakable.h b/Kernel/Library/LockWeakable.h index d97a064a19..ed3e4367d5 100644 --- a/Kernel/Library/ThreadSafeWeakable.h +++ b/Kernel/Library/LockWeakable.h @@ -9,30 +9,30 @@ #include <AK/Assertions.h> #include <AK/Atomic.h> #include <AK/AtomicRefCounted.h> -#include <AK/RefPtr.h> #include <AK/StdLibExtras.h> #include <Kernel/Arch/Processor.h> #include <Kernel/Arch/ScopedCritical.h> +#include <Kernel/Library/LockRefPtr.h> namespace AK { template<typename T> -class Weakable; +class LockWeakable; template<typename T> -class WeakPtr; +class LockWeakPtr; class WeakLink final : public AtomicRefCounted<WeakLink> { template<typename T> - friend class Weakable; + friend class LockWeakable; template<typename T> - friend class WeakPtr; + friend class LockWeakPtr; public: - template<typename T, typename PtrTraits = RefPtrTraits<T>> - RefPtr<T, PtrTraits> strong_ref() const + template<typename T, typename PtrTraits = LockRefPtrTraits<T>> + LockRefPtr<T, PtrTraits> strong_ref() const requires(IsBaseOf<AtomicRefCountedBase, T>) { - RefPtr<T, PtrTraits> ref; + LockRefPtr<T, PtrTraits> ref; { // We don't want to be preempted while we are trying to obtain @@ -41,7 +41,7 @@ public: if (!(m_consumers.fetch_add(1u << 1, AK::MemoryOrder::memory_order_acquire) & 1u)) { T* ptr = (T*)m_ptr.load(AK::MemoryOrder::memory_order_acquire); if (ptr && ptr->try_ref()) - ref = adopt_ref(*ptr); + ref = adopt_lock_ref(*ptr); } m_consumers.fetch_sub(1u << 1, AK::MemoryOrder::memory_order_release); } @@ -91,18 +91,18 @@ private: }; template<typename T> -class Weakable { +class LockWeakable { private: class Link; public: template<typename U = T> - ErrorOr<WeakPtr<U>> try_make_weak_ptr() const; + ErrorOr<LockWeakPtr<U>> try_make_weak_ptr() const; protected: - Weakable() = default; + LockWeakable() = default; - ~Weakable() + ~LockWeakable() { m_being_destroyed.store(true, AK::MemoryOrder::memory_order_release); revoke_weak_ptrs(); @@ -115,10 +115,10 @@ protected: } private: - mutable RefPtr<WeakLink> m_link; + mutable LockRefPtr<WeakLink> m_link; Atomic<bool> m_being_destroyed { false }; }; } -using AK::Weakable; +using AK::LockWeakable; diff --git a/Kernel/Library/ThreadSafeNonnullRefPtr.h b/Kernel/Library/NonnullLockRefPtr.h index de7e08cbc2..44289a3b55 100644 --- a/Kernel/Library/ThreadSafeNonnullRefPtr.h +++ b/Kernel/Library/NonnullLockRefPtr.h @@ -9,6 +9,7 @@ #include <AK/Assertions.h> #include <AK/Atomic.h> #include <AK/Format.h> +#include <AK/NonnullRefPtr.h> #include <AK/Traits.h> #include <AK/Types.h> #ifdef KERNEL @@ -16,104 +17,90 @@ # include <Kernel/Arch/ScopedCritical.h> #endif -#define THREADSAFENONNULLREFPTR_SCRUB_BYTE 0xa1 +#define NONNULLLOCKREFPTR_SCRUB_BYTE 0xa1 namespace AK { template<typename T> class OwnPtr; template<typename T, typename PtrTraits> -class RefPtr; +class LockRefPtr; template<typename T> -ALWAYS_INLINE void ref_if_not_null(T* ptr) -{ - if (ptr) - ptr->ref(); -} - -template<typename T> -ALWAYS_INLINE void unref_if_not_null(T* ptr) -{ - if (ptr) - ptr->unref(); -} - -template<typename T> -class [[nodiscard]] NonnullRefPtr { +class [[nodiscard]] NonnullLockRefPtr { template<typename U, typename P> - friend class RefPtr; + friend class LockRefPtr; template<typename U> - friend class NonnullRefPtr; + friend class NonnullLockRefPtr; template<typename U> - friend class WeakPtr; + friend class LockWeakPtr; public: using ElementType = T; enum AdoptTag { Adopt }; - ALWAYS_INLINE NonnullRefPtr(const T& object) + ALWAYS_INLINE NonnullLockRefPtr(T const& object) : m_bits((FlatPtr)&object) { VERIFY(!(m_bits & 1)); const_cast<T&>(object).ref(); } template<typename U> - ALWAYS_INLINE NonnullRefPtr(const U& object) requires(IsConvertible<U*, T*>) - : m_bits((FlatPtr) static_cast<const T*>(&object)) + ALWAYS_INLINE NonnullLockRefPtr(U const& object) requires(IsConvertible<U*, T*>) + : m_bits((FlatPtr) static_cast<T const*>(&object)) { VERIFY(!(m_bits & 1)); - const_cast<T&>(static_cast<const T&>(object)).ref(); + const_cast<T&>(static_cast<T const&>(object)).ref(); } - ALWAYS_INLINE NonnullRefPtr(AdoptTag, T& object) + ALWAYS_INLINE NonnullLockRefPtr(AdoptTag, T& object) : m_bits((FlatPtr)&object) { VERIFY(!(m_bits & 1)); } - ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr&& other) + ALWAYS_INLINE NonnullLockRefPtr(NonnullLockRefPtr&& other) : m_bits((FlatPtr)&other.leak_ref()) { VERIFY(!(m_bits & 1)); } template<typename U> - ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr<U>&& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE NonnullLockRefPtr(NonnullLockRefPtr<U>&& other) requires(IsConvertible<U*, T*>) : m_bits((FlatPtr)&other.leak_ref()) { VERIFY(!(m_bits & 1)); } - ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr const& other) + ALWAYS_INLINE NonnullLockRefPtr(NonnullLockRefPtr const& other) : m_bits((FlatPtr)other.add_ref()) { VERIFY(!(m_bits & 1)); } template<typename U> - ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr<U> const& other) requires(IsConvertible<U*, T*>) + ALWAYS_INLINE NonnullLockRefPtr(NonnullLockRefPtr<U> const& other) requires(IsConvertible<U*, T*>) : m_bits((FlatPtr)other.add_ref()) { VERIFY(!(m_bits & 1)); } - ALWAYS_INLINE ~NonnullRefPtr() + ALWAYS_INLINE ~NonnullLockRefPtr() { assign(nullptr); #ifdef SANITIZE_PTRS - m_bits.store(explode_byte(THREADSAFENONNULLREFPTR_SCRUB_BYTE), AK::MemoryOrder::memory_order_relaxed); + m_bits.store(explode_byte(NONNULLLOCKREFPTR_SCRUB_BYTE), AK::MemoryOrder::memory_order_relaxed); #endif } template<typename U> - NonnullRefPtr(OwnPtr<U> const&) = delete; + NonnullLockRefPtr(OwnPtr<U> const&) = delete; template<typename U> - NonnullRefPtr& operator=(OwnPtr<U> const&) = delete; + NonnullLockRefPtr& operator=(OwnPtr<U> const&) = delete; template<typename U> - NonnullRefPtr(RefPtr<U> const&) = delete; + NonnullLockRefPtr(LockRefPtr<U> const&) = delete; template<typename U> - NonnullRefPtr& operator=(RefPtr<U> const&) = delete; - NonnullRefPtr(RefPtr<T> const&) = delete; - NonnullRefPtr& operator=(RefPtr<T> const&) = delete; + NonnullLockRefPtr& operator=(LockRefPtr<U> const&) = delete; + NonnullLockRefPtr(LockRefPtr<T> const&) = delete; + NonnullLockRefPtr& operator=(LockRefPtr<T> const&) = delete; - NonnullRefPtr& operator=(NonnullRefPtr const& other) + NonnullLockRefPtr& operator=(NonnullLockRefPtr const& other) { if (this != &other) assign(other.add_ref()); @@ -121,13 +108,13 @@ public: } template<typename U> - NonnullRefPtr& operator=(NonnullRefPtr<U> const& other) requires(IsConvertible<U*, T*>) + NonnullLockRefPtr& operator=(NonnullLockRefPtr<U> const& other) requires(IsConvertible<U*, T*>) { assign(other.add_ref()); return *this; } - ALWAYS_INLINE NonnullRefPtr& operator=(NonnullRefPtr&& other) + ALWAYS_INLINE NonnullLockRefPtr& operator=(NonnullLockRefPtr&& other) { if (this != &other) assign(&other.leak_ref()); @@ -135,13 +122,13 @@ public: } template<typename U> - NonnullRefPtr& operator=(NonnullRefPtr<U>&& other) requires(IsConvertible<U*, T*>) + NonnullLockRefPtr& operator=(NonnullLockRefPtr<U>&& other) requires(IsConvertible<U*, T*>) { assign(&other.leak_ref()); return *this; } - NonnullRefPtr& operator=(const T& object) + NonnullLockRefPtr& operator=(T const& object) { const_cast<T&>(object).ref(); assign(const_cast<T*>(&object)); @@ -159,7 +146,7 @@ public: { return as_nonnull_ptr(); } - ALWAYS_INLINE RETURNS_NONNULL const T* ptr() const + ALWAYS_INLINE RETURNS_NONNULL T const* ptr() const { return as_nonnull_ptr(); } @@ -168,7 +155,7 @@ public: { return as_nonnull_ptr(); } - ALWAYS_INLINE RETURNS_NONNULL const T* operator->() const + ALWAYS_INLINE RETURNS_NONNULL T const* operator->() const { return as_nonnull_ptr(); } @@ -177,7 +164,7 @@ public: { return *as_nonnull_ptr(); } - ALWAYS_INLINE const T& operator*() const + ALWAYS_INLINE T const& operator*() const { return *as_nonnull_ptr(); } @@ -186,7 +173,7 @@ public: { return as_nonnull_ptr(); } - ALWAYS_INLINE RETURNS_NONNULL operator const T*() const + ALWAYS_INLINE RETURNS_NONNULL operator T const*() const { return as_nonnull_ptr(); } @@ -195,7 +182,7 @@ public: { return *as_nonnull_ptr(); } - ALWAYS_INLINE operator const T&() const + ALWAYS_INLINE operator T const&() const { return *as_nonnull_ptr(); } @@ -203,7 +190,7 @@ public: operator bool() const = delete; bool operator!() const = delete; - void swap(NonnullRefPtr& other) + void swap(NonnullLockRefPtr& other) { if (this == &other) return; @@ -215,7 +202,7 @@ public: } template<typename U> - void swap(NonnullRefPtr<U>& other) requires(IsConvertible<U*, T*>) + void swap(NonnullLockRefPtr<U>& other) requires(IsConvertible<U*, T*>) { // NOTE: swap is not atomic! U* other_ptr = other.exchange(nullptr); @@ -225,7 +212,7 @@ public: // clang-format off private: - NonnullRefPtr() = delete; + NonnullLockRefPtr() = delete; // clang-format on ALWAYS_INLINE T* as_ptr() const @@ -317,21 +304,21 @@ private: }; template<typename T> -inline NonnullRefPtr<T> adopt_ref(T& object) +inline NonnullLockRefPtr<T> adopt_lock_ref(T& object) { - return NonnullRefPtr<T>(NonnullRefPtr<T>::Adopt, object); + return NonnullLockRefPtr<T>(NonnullLockRefPtr<T>::Adopt, object); } template<typename T> -struct Formatter<NonnullRefPtr<T>> : Formatter<const T*> { - ErrorOr<void> format(FormatBuilder& builder, NonnullRefPtr<T> const& value) +struct Formatter<NonnullLockRefPtr<T>> : Formatter<T const*> { + ErrorOr<void> format(FormatBuilder& builder, NonnullLockRefPtr<T> const& value) { - return Formatter<const T*>::format(builder, value.ptr()); + return Formatter<T const*>::format(builder, value.ptr()); } }; template<typename T, typename U> -inline void swap(NonnullRefPtr<T>& a, NonnullRefPtr<U>& b) requires(IsConvertible<U*, T*>) +inline void swap(NonnullLockRefPtr<T>& a, NonnullLockRefPtr<U>& b) requires(IsConvertible<U*, T*>) { a.swap(b); } @@ -339,12 +326,12 @@ inline void swap(NonnullRefPtr<T>& a, NonnullRefPtr<U>& b) requires(IsConvertibl } template<typename T> -struct Traits<NonnullRefPtr<T>> : public GenericTraits<NonnullRefPtr<T>> { +struct Traits<NonnullLockRefPtr<T>> : public GenericTraits<NonnullLockRefPtr<T>> { using PeekType = T*; - using ConstPeekType = const T*; - static unsigned hash(NonnullRefPtr<T> const& p) { return ptr_hash(p.ptr()); } - static bool equals(NonnullRefPtr<T> const& a, NonnullRefPtr<T> const& b) { return a.ptr() == b.ptr(); } + using ConstPeekType = T const*; + static unsigned hash(NonnullLockRefPtr<T> const& p) { return ptr_hash(p.ptr()); } + static bool equals(NonnullLockRefPtr<T> const& a, NonnullLockRefPtr<T> const& b) { return a.ptr() == b.ptr(); } }; -using AK::adopt_ref; -using AK::NonnullRefPtr; +using AK::adopt_lock_ref; +using AK::NonnullLockRefPtr; diff --git a/Kernel/Library/NonnullLockRefPtrVector.h b/Kernel/Library/NonnullLockRefPtrVector.h new file mode 100644 index 0000000000..dea5ad2fc0 --- /dev/null +++ b/Kernel/Library/NonnullLockRefPtrVector.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/NonnullPtrVector.h> +#include <Kernel/Library/NonnullLockRefPtr.h> + +namespace AK { + +template<typename T, size_t inline_capacity> +class NonnullLockRefPtrVector : public NonnullPtrVector<NonnullLockRefPtr<T>, inline_capacity> { + using NonnullPtrVector<NonnullLockRefPtr<T>, inline_capacity>::NonnullPtrVector; +}; + +} + +using AK::NonnullLockRefPtrVector; |