1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 18:47:44 +00:00

AK+Kernel: Make automatically locking RefPtr & co a kernel-only thing

Some time ago, automatic locking was added to the AK smart pointers to
paper over various race conditions in the kernel. Until we've actually
solved the issues in the kernel, we're stuck with the locking.

However, we don't need to punish single-threaded userspace programs with
the high cost of locking. This patch moves the thread-safe variants of
RefPtr, NonnullRefPtr, WeakPtr and RefCounted into Kernel/Library/.
This commit is contained in:
Andreas Kling 2021-10-07 19:12:37 +02:00
parent ca060d8566
commit 5b1f697460
8 changed files with 1418 additions and 470 deletions

View file

@ -6,7 +6,11 @@
#pragma once
#include <AK/Weakable.h>
#ifdef KERNEL
# include <Kernel/Library/ThreadSafeWeakPtr.h>
#else
# include <AK/Weakable.h>
namespace AK {
@ -65,21 +69,16 @@ public:
}
template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
WeakPtr(const RefPtr<U>& object)
WeakPtr(RefPtr<U> const& object)
{
object.do_while_locked([&](U* obj) {
if (obj)
m_link = obj->template make_weak_ptr<U>().take_link();
});
if (object)
m_link = object->template make_weak_ptr<U>().take_link();
}
template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
WeakPtr(const NonnullRefPtr<U>& object)
WeakPtr(NonnullRefPtr<U> const& object)
{
object.do_while_locked([&](U* obj) {
if (obj)
m_link = obj->template make_weak_ptr<U>().take_link();
});
m_link = object->template make_weak_ptr<U>().take_link();
}
template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
@ -102,61 +101,36 @@ public:
template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
WeakPtr& operator=(const RefPtr<U>& object)
{
object.do_while_locked([&](U* obj) {
if (obj)
m_link = obj->template make_weak_ptr<U>().take_link();
else
m_link = nullptr;
});
if (object)
m_link = object->template make_weak_ptr<U>().take_link();
else
m_link = nullptr;
return *this;
}
template<typename U, typename EnableIf<IsBaseOf<T, U>>::Type* = nullptr>
WeakPtr& operator=(const NonnullRefPtr<U>& object)
{
object.do_while_locked([&](U* obj) {
if (obj)
m_link = obj->template make_weak_ptr<U>().take_link();
else
m_link = nullptr;
});
m_link = object->template make_weak_ptr<U>().take_link();
return *this;
}
[[nodiscard]] RefPtr<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
// 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;
// Using do_while_locked protects against a race with clear()!
m_link.do_while_locked([&](WeakLink* link) {
if (link)
ref = link->template strong_ref<T>();
});
return ref;
return RefPtr<T> { ptr() };
}
#ifndef KERNEL
// A lot of user mode code is single-threaded. But for kernel mode code
// this is generally not true as everything is multi-threaded. So make
// these shortcuts and aliases only available to non-kernel code.
T* ptr() const { return unsafe_ptr(); }
T* operator->() { return unsafe_ptr(); }
const T* operator->() const { return unsafe_ptr(); }
operator const T*() const { return unsafe_ptr(); }
operator T*() { return unsafe_ptr(); }
#endif
[[nodiscard]] T* unsafe_ptr() const
{
T* ptr = nullptr;
m_link.do_while_locked([&](WeakLink* link) {
if (link)
ptr = link->unsafe_ptr<T>();
});
return ptr;
if (m_link)
return m_link->template unsafe_ptr<T>();
return nullptr;
}
operator bool() const { return m_link ? !m_link->is_null() : false; }
@ -219,12 +193,7 @@ template<typename T>
struct Formatter<WeakPtr<T>> : Formatter<const T*> {
void format(FormatBuilder& builder, const WeakPtr<T>& value)
{
#ifdef KERNEL
auto ref = value.strong_ref();
Formatter<const T*>::format(builder, ref.ptr());
#else
Formatter<const T*>::format(builder, value.ptr());
#endif
}
};
@ -240,3 +209,4 @@ WeakPtr<T> try_make_weak_ptr(const T* ptr)
}
using AK::WeakPtr;
#endif