diff options
author | Jean-Baptiste Boric <jblbeurope@gmail.com> | 2021-07-19 00:17:17 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-07 11:48:00 +0200 |
commit | 39ceefa5ddc01c422d1c85b919cb1ef3bbf68ff2 (patch) | |
tree | 90c1462a6656e6cf44c0692cd28b6fcbed48df75 | |
parent | 019ad8a507aaed2475aa179da3ffeecbf57feac7 (diff) | |
download | serenity-39ceefa5ddc01c422d1c85b919cb1ef3bbf68ff2.zip |
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.
-rw-r--r-- | Kernel/Locking/NonnullRefContendedPtr.h | 17 | ||||
-rw-r--r-- | Kernel/Locking/NonnullRefContendedPtrVector.h | 17 | ||||
-rw-r--r-- | Kernel/Locking/RefContendedPtr.h | 17 | ||||
-rw-r--r-- | Kernel/Locking/RefCountedContended.h | 77 |
4 files changed, 128 insertions, 0 deletions
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 <AK/NonnullRefPtr.h> +#include <Kernel/Locking/RefCountedContended.h> + +namespace Kernel { + +template<typename T> +using NonnullRefContendedPtr = NonnullRefPtr<RefCountedContended<T>>; + +} 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 <AK/NonnullPtrVector.h> +#include <Kernel/Locking/NonnullRefContendedPtr.h> + +namespace Kernel { + +template<typename T, size_t inline_capacity = 0> +using NonnullRefContendedPtrVector = AK::NonnullPtrVector<NonnullRefContendedPtr<T>, 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 <AK/RefPtr.h> +#include <Kernel/Locking/RefCountedContended.h> + +namespace Kernel { + +template<typename T> +using RefContendedPtr = RefPtr<RefCountedContended<T>>; + +} 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 <AK/RefCounted.h> +#include <Kernel/Locking/ContendedResource.h> +#include <Kernel/Locking/Mutex.h> + +namespace Kernel { + +template<typename T> +class RefCountedContended : public ContendedResource + , public AK::RefCountedBase { + AK_MAKE_NONCOPYABLE(RefCountedContended); + AK_MAKE_NONMOVABLE(RefCountedContended); + +protected: + using LockedShared = LockedResource<T const, LockMode::Shared>; + using LockedExclusive = LockedResource<T, LockMode::Exclusive>; + + LockedShared lock_shared() const { return LockedShared(static_cast<T const*>(this), this->ContendedResource::m_mutex); } + LockedExclusive lock_exclusive() { return LockedExclusive(static_cast<T*>(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<T*>(const_cast<RefCountedContended*>(this)->lock_exclusive().get())); + delete static_cast<const T*>(this); + return true; + } else if (new_ref_count == 1) { + AK::call_one_ref_left_if_present(static_cast<T*>(const_cast<RefCountedContended*>(this)->lock_exclusive().get())); + } + return false; + } + + template<typename Callback> + decltype(auto) with_shared(Callback callback) const + { + auto lock = lock_shared(); + return callback(*lock); + } + + template<typename Callback> + decltype(auto) with_exclusive(Callback callback) + { + auto lock = lock_exclusive(); + return callback(*lock); + } + + template<typename Callback> + void for_each_shared(Callback callback) const + { + with_shared([&](const auto& value) { + for (auto& item : value) + callback(item); + }); + } + + template<typename Callback> + void for_each_exclusive(Callback callback) + { + with_exclusive([&](auto& value) { + for (auto& item : value) + callback(item); + }); + } +}; + +} |