From 39ceefa5ddc01c422d1c85b919cb1ef3bbf68ff2 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Mon, 19 Jul 2021 00:17:17 +0200 Subject: [PATCH] Kernel: Implement contended, ref-counted resource framework This is some syntaxic sugar to use a ContendedResource object with reference counting. This effectively dissociates merely holding a reference to an object and actually using the object in a way that requires locking it against concurrent use. --- Kernel/Locking/NonnullRefContendedPtr.h | 17 ++++ Kernel/Locking/NonnullRefContendedPtrVector.h | 17 ++++ Kernel/Locking/RefContendedPtr.h | 17 ++++ Kernel/Locking/RefCountedContended.h | 77 +++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 Kernel/Locking/NonnullRefContendedPtr.h create mode 100644 Kernel/Locking/NonnullRefContendedPtrVector.h create mode 100644 Kernel/Locking/RefContendedPtr.h create mode 100644 Kernel/Locking/RefCountedContended.h diff --git a/Kernel/Locking/NonnullRefContendedPtr.h b/Kernel/Locking/NonnullRefContendedPtr.h new file mode 100644 index 0000000000..47ee850805 --- /dev/null +++ b/Kernel/Locking/NonnullRefContendedPtr.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Kernel { + +template +using NonnullRefContendedPtr = NonnullRefPtr>; + +} diff --git a/Kernel/Locking/NonnullRefContendedPtrVector.h b/Kernel/Locking/NonnullRefContendedPtrVector.h new file mode 100644 index 0000000000..bb7f2cbf2c --- /dev/null +++ b/Kernel/Locking/NonnullRefContendedPtrVector.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Kernel { + +template +using NonnullRefContendedPtrVector = AK::NonnullPtrVector, inline_capacity>; + +} diff --git a/Kernel/Locking/RefContendedPtr.h b/Kernel/Locking/RefContendedPtr.h new file mode 100644 index 0000000000..314406eca9 --- /dev/null +++ b/Kernel/Locking/RefContendedPtr.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Kernel { + +template +using RefContendedPtr = RefPtr>; + +} diff --git a/Kernel/Locking/RefCountedContended.h b/Kernel/Locking/RefCountedContended.h new file mode 100644 index 0000000000..507c88788b --- /dev/null +++ b/Kernel/Locking/RefCountedContended.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Kernel { + +template +class RefCountedContended : public ContendedResource + , public AK::RefCountedBase { + AK_MAKE_NONCOPYABLE(RefCountedContended); + AK_MAKE_NONMOVABLE(RefCountedContended); + +protected: + using LockedShared = LockedResource; + using LockedExclusive = LockedResource; + + LockedShared lock_shared() const { return LockedShared(static_cast(this), this->ContendedResource::m_mutex); } + LockedExclusive lock_exclusive() { return LockedExclusive(static_cast(this), this->ContendedResource::m_mutex); } + +public: + RefCountedContended() = default; + + bool unref() const + { + auto new_ref_count = deref_base(); + if (new_ref_count == 0) { + AK::call_will_be_destroyed_if_present(static_cast(const_cast(this)->lock_exclusive().get())); + delete static_cast(this); + return true; + } else if (new_ref_count == 1) { + AK::call_one_ref_left_if_present(static_cast(const_cast(this)->lock_exclusive().get())); + } + return false; + } + + template + decltype(auto) with_shared(Callback callback) const + { + auto lock = lock_shared(); + return callback(*lock); + } + + template + decltype(auto) with_exclusive(Callback callback) + { + auto lock = lock_exclusive(); + return callback(*lock); + } + + template + void for_each_shared(Callback callback) const + { + with_shared([&](const auto& value) { + for (auto& item : value) + callback(item); + }); + } + + template + void for_each_exclusive(Callback callback) + { + with_exclusive([&](auto& value) { + for (auto& item : value) + callback(item); + }); + } +}; + +}