summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Boric <jblbeurope@gmail.com>2021-07-19 00:17:17 +0200
committerAndreas Kling <kling@serenityos.org>2021-08-07 11:48:00 +0200
commit39ceefa5ddc01c422d1c85b919cb1ef3bbf68ff2 (patch)
tree90c1462a6656e6cf44c0692cd28b6fcbed48df75
parent019ad8a507aaed2475aa179da3ffeecbf57feac7 (diff)
downloadserenity-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.h17
-rw-r--r--Kernel/Locking/NonnullRefContendedPtrVector.h17
-rw-r--r--Kernel/Locking/RefContendedPtr.h17
-rw-r--r--Kernel/Locking/RefCountedContended.h77
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);
+ });
+ }
+};
+
+}