mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-25 02:38:59 +00:00
LibThreading: Add RWLock and RWLockedProtected
This commit is contained in:
parent
06d522f017
commit
5cc90f848f
Notes:
sideshowbarker
2024-07-16 23:17:55 +09:00
Author: https://github.com/alimpfard
Commit: 5cc90f848f
Pull-request: https://github.com/SerenityOS/serenity/pull/24313
Reviewed-by: https://github.com/Zaggy1024
2 changed files with 180 additions and 0 deletions
108
Userland/Libraries/LibThreading/RWLock.h
Normal file
108
Userland/Libraries/LibThreading/RWLock.h
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Assertions.h>
|
||||||
|
#include <AK/Noncopyable.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
namespace Threading {
|
||||||
|
|
||||||
|
class RWLock {
|
||||||
|
AK_MAKE_NONCOPYABLE(RWLock);
|
||||||
|
AK_MAKE_NONMOVABLE(RWLock);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RWLock()
|
||||||
|
{
|
||||||
|
pthread_rwlock_init(&m_rwlock, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
~RWLock()
|
||||||
|
{
|
||||||
|
VERIFY(!m_write_locked);
|
||||||
|
pthread_rwlock_destroy(&m_rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_read();
|
||||||
|
void lock_write();
|
||||||
|
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
pthread_rwlock_t m_rwlock;
|
||||||
|
bool m_write_locked { false };
|
||||||
|
bool m_read_locked_with_write_lock { false };
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class LockMode {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
};
|
||||||
|
template<LockMode mode>
|
||||||
|
class RWLockLocker {
|
||||||
|
AK_MAKE_NONCOPYABLE(RWLockLocker);
|
||||||
|
AK_MAKE_NONMOVABLE(RWLockLocker);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ALWAYS_INLINE explicit RWLockLocker(RWLock& l)
|
||||||
|
: m_lock(l)
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE ~RWLockLocker()
|
||||||
|
{
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void unlock()
|
||||||
|
{
|
||||||
|
m_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void lock()
|
||||||
|
{
|
||||||
|
if constexpr (mode == LockMode::Read)
|
||||||
|
m_lock.lock_read();
|
||||||
|
else
|
||||||
|
m_lock.lock_write();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RWLock& m_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
ALWAYS_INLINE void RWLock::lock_read()
|
||||||
|
{
|
||||||
|
auto rc = pthread_rwlock_rdlock(&m_rwlock);
|
||||||
|
if (rc == EDEADLK) {
|
||||||
|
// We're already holding the write lock, so we can just return.
|
||||||
|
m_read_locked_with_write_lock = true;
|
||||||
|
} else {
|
||||||
|
VERIFY(rc == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void RWLock::lock_write()
|
||||||
|
{
|
||||||
|
auto rc = pthread_rwlock_wrlock(&m_rwlock);
|
||||||
|
VERIFY(rc == 0);
|
||||||
|
m_write_locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void RWLock::unlock()
|
||||||
|
{
|
||||||
|
m_write_locked = false;
|
||||||
|
auto needs_unlock = !m_read_locked_with_write_lock;
|
||||||
|
m_read_locked_with_write_lock = false;
|
||||||
|
if (needs_unlock)
|
||||||
|
pthread_rwlock_unlock(&m_rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
Userland/Libraries/LibThreading/RWLockProtected.h
Normal file
72
Userland/Libraries/LibThreading/RWLockProtected.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Concepts.h>
|
||||||
|
#include <AK/Noncopyable.h>
|
||||||
|
#include <LibThreading/RWLock.h>
|
||||||
|
|
||||||
|
namespace Threading {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class RWLockProtected {
|
||||||
|
AK_MAKE_NONCOPYABLE(RWLockProtected);
|
||||||
|
AK_MAKE_NONMOVABLE(RWLockProtected);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using ProtectedType = T;
|
||||||
|
|
||||||
|
ALWAYS_INLINE RWLockProtected() = default;
|
||||||
|
ALWAYS_INLINE RWLockProtected(T&& value)
|
||||||
|
: m_value(move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE explicit RWLockProtected(T& value)
|
||||||
|
: m_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
requires(requires { declval<Callback>()(declval<T const&>()); })
|
||||||
|
decltype(auto) with_read_locked(Callback callback) const
|
||||||
|
{
|
||||||
|
auto lock = this->lock_read();
|
||||||
|
return callback(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Callback>
|
||||||
|
decltype(auto) with_write_locked(Callback callback)
|
||||||
|
{
|
||||||
|
auto lock = this->lock_write();
|
||||||
|
return callback(m_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<VoidFunction<T> Callback>
|
||||||
|
void for_each_locked(Callback callback)
|
||||||
|
{
|
||||||
|
with_read_locked([&](auto const& value) {
|
||||||
|
for (auto& item : value)
|
||||||
|
callback(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] ALWAYS_INLINE RWLockLocker<LockMode::Read> lock_read() const
|
||||||
|
{
|
||||||
|
return RWLockLocker<LockMode::Read> { m_lock };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] ALWAYS_INLINE RWLockLocker<LockMode::Write> lock_write()
|
||||||
|
{
|
||||||
|
return RWLockLocker<LockMode::Write> { m_lock };
|
||||||
|
}
|
||||||
|
|
||||||
|
T m_value;
|
||||||
|
mutable RWLock m_lock {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue