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".
This commit is contained in:
parent
39ceefa5dd
commit
75260bff92
Notes:
sideshowbarker
2024-07-18 07:20:37 +09:00
Author: https://github.com/boricj Commit: https://github.com/SerenityOS/serenity/commit/75260bff92f Pull-request: https://github.com/SerenityOS/serenity/pull/8851 Reviewed-by: https://github.com/awesomekling ✅ Reviewed-by: https://github.com/bgianfo
1 changed files with 64 additions and 0 deletions
64
Kernel/Locking/ProtectedValue.h
Normal file
64
Kernel/Locking/ProtectedValue.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2021, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Locking/ContendedResource.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
template<typename T>
|
||||
class ProtectedValue : private T
|
||||
, public ContendedResource {
|
||||
AK_MAKE_NONCOPYABLE(ProtectedValue);
|
||||
AK_MAKE_NONMOVABLE(ProtectedValue);
|
||||
|
||||
protected:
|
||||
using LockedShared = LockedResource<T const, LockMode::Shared>;
|
||||
using LockedExclusive = LockedResource<T, LockMode::Exclusive>;
|
||||
|
||||
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<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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue