From 75260bff92fa75033c92cf09d0ab6cf55b515c85 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Sun, 18 Jul 2021 10:03:10 +0200 Subject: [PATCH] Kernel: Introduce ProtectedValue A protected value is a variable with enforced locking semantics. The value is protected with a Mutex and can only be accessed through a Locked object that holds a MutexLocker to said Mutex. Therefore, the value itself cannot be accessed except through the proper locking mechanism, which enforces correct locking semantics. The Locked object has knowledge of shared and exclusive lock types and will only return const-correct references and pointers. This should help catch incorrect locking usage where a shared lock is acquired but the user then modifies the locked value. This is not a perfect solution because dereferencing the Locked object returns the value, so the caller could defeat the protected value semantics once it acquires a lock by keeping a pointer or a reference to the value around. Then again, this is C++ and we can't protect against malicious users from within the kernel anyways, but we can raise the threshold above "didn't pay attention". --- Kernel/Locking/ProtectedValue.h | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Kernel/Locking/ProtectedValue.h diff --git a/Kernel/Locking/ProtectedValue.h b/Kernel/Locking/ProtectedValue.h new file mode 100644 index 0000000000..676f932473 --- /dev/null +++ b/Kernel/Locking/ProtectedValue.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace Kernel { + +template +class ProtectedValue : private T + , public ContendedResource { + AK_MAKE_NONCOPYABLE(ProtectedValue); + AK_MAKE_NONMOVABLE(ProtectedValue); + +protected: + using LockedShared = LockedResource; + using LockedExclusive = LockedResource; + + LockedShared lock_shared() const { return LockedShared(this, this->ContendedResource::m_mutex); } + LockedExclusive lock_exclusive() { return LockedExclusive(this, this->ContendedResource::m_mutex); } + +public: + using T::T; + + ProtectedValue() = default; + + 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); + }); + } +}; + +}