LibSync: Remove pthread from the RWLock interface
This commit removes any use of pthread.h from the RWLock header. It also adds a win32 implementation of RWLock. Support for interprocess RWLocks is left to a later PR. Due to the API design of SRWLock the unlock methods must match the lock method.
This commit is contained in:
parent
50be9493d2
commit
125b399a72
4 changed files with 196 additions and 52 deletions
|
|
@ -1,7 +1,7 @@
|
|||
if (WIN32)
|
||||
set(SOURCES MutexWindows.cpp ConditionVariableWindows.cpp)
|
||||
set(SOURCES MutexWindows.cpp ConditionVariableWindows.cpp RWLockWindows.cpp)
|
||||
else()
|
||||
set(SOURCES MutexPOSIX.cpp ConditionVariablePOSIX.cpp)
|
||||
set(SOURCES MutexPOSIX.cpp ConditionVariablePOSIX.cpp RWLockPOSIX.cpp)
|
||||
endif()
|
||||
|
||||
ladybird_lib(LibSync sync EXPLICIT_SYMBOL_EXPORT)
|
||||
|
|
|
|||
|
|
@ -1,52 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
* Copyright (c) 2025, Ryszard Goc <ryszardgoc@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/Platform.h>
|
||||
#include <AK/Types.h>
|
||||
#include <pthread.h>
|
||||
#include <LibSync/Export.h>
|
||||
|
||||
#if !defined(AK_OS_WINDOWS)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
namespace Sync {
|
||||
|
||||
class RWLock {
|
||||
// TODO: Implement interprocess RWLocks. This needs a hand-rolled implementation for win32.
|
||||
class SYNC_API RWLock {
|
||||
AK_MAKE_NONCOPYABLE(RWLock);
|
||||
AK_MAKE_NONMOVABLE(RWLock);
|
||||
|
||||
public:
|
||||
RWLock()
|
||||
{
|
||||
pthread_rwlock_init(&m_rwlock, nullptr);
|
||||
}
|
||||
RWLock();
|
||||
~RWLock();
|
||||
|
||||
~RWLock()
|
||||
{
|
||||
VERIFY(!m_write_locked);
|
||||
pthread_rwlock_destroy(&m_rwlock);
|
||||
}
|
||||
bool try_lock_read();
|
||||
bool try_lock_write();
|
||||
|
||||
// Recursively acquiring a RWLock is not supported
|
||||
void lock_read();
|
||||
void lock_write();
|
||||
|
||||
// NOTE: While the pthread api has one unlock method, the Win32 api has separate ones per lock mode
|
||||
void unlock_read();
|
||||
void unlock_write();
|
||||
|
||||
private:
|
||||
pthread_rwlock_t m_rwlock;
|
||||
bool m_write_locked { false };
|
||||
bool m_read_locked_with_write_lock { false };
|
||||
#ifdef AK_OS_WINDOWS
|
||||
using StorageType = void*;
|
||||
#else
|
||||
using StorageType = pthread_rwlock_t;
|
||||
#endif
|
||||
|
||||
alignas(StorageType) unsigned char m_storage[sizeof(StorageType)];
|
||||
};
|
||||
|
||||
enum class LockMode {
|
||||
enum class LockMode : u8 {
|
||||
Read,
|
||||
Write,
|
||||
};
|
||||
|
||||
template<LockMode mode>
|
||||
class RWLockLocker {
|
||||
class SYNC_API RWLockLocker {
|
||||
AK_MAKE_NONCOPYABLE(RWLockLocker);
|
||||
AK_MAKE_NONMOVABLE(RWLockLocker);
|
||||
|
||||
|
|
@ -82,37 +89,4 @@ 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_read()
|
||||
{
|
||||
if (m_read_locked_with_write_lock) {
|
||||
m_read_locked_with_write_lock = false;
|
||||
return;
|
||||
}
|
||||
pthread_rwlock_unlock(&m_rwlock);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void RWLock::unlock_write()
|
||||
{
|
||||
m_write_locked = false;
|
||||
pthread_rwlock_unlock(&m_rwlock);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
105
Libraries/LibSync/RWLockPOSIX.cpp
Normal file
105
Libraries/LibSync/RWLockPOSIX.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
* Copyright (c) 2025, Ryszard Goc <ryszardgoc@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Platform.h>
|
||||
#include <LibSync/Export.h>
|
||||
#include <LibSync/RWLock.h>
|
||||
#include <new>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace Sync {
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE pthread_rwlock_t* to_impl(void* ptr)
|
||||
{
|
||||
return reinterpret_cast<pthread_rwlock_t*>(ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RWLock::RWLock()
|
||||
{
|
||||
static_assert(sizeof(pthread_rwlock_t) == sizeof(m_storage));
|
||||
auto* rwlock_ptr = new (m_storage) pthread_rwlock_t;
|
||||
int result = pthread_rwlock_init(rwlock_ptr, nullptr);
|
||||
if (result != 0) {
|
||||
warnln("pthread_rwlock_unlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
RWLock::~RWLock()
|
||||
{
|
||||
int result = pthread_rwlock_destroy(to_impl(m_storage));
|
||||
if (result != 0) {
|
||||
warnln("pthread_rwlock_destroy failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
bool RWLock::try_lock_read()
|
||||
{
|
||||
int result = pthread_rwlock_tryrdlock(to_impl(m_storage));
|
||||
if (result == 0)
|
||||
return true;
|
||||
if (result == EBUSY)
|
||||
return false;
|
||||
warnln("pthread_rwlock_trywrlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
bool RWLock::try_lock_write()
|
||||
{
|
||||
int result = pthread_rwlock_trywrlock(to_impl(m_storage));
|
||||
if (result == 0)
|
||||
return true;
|
||||
if (result == EBUSY)
|
||||
return false;
|
||||
warnln("pthread_rwlock_trywrlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
void RWLock::lock_read()
|
||||
{
|
||||
int result = pthread_rwlock_rdlock(to_impl(m_storage));
|
||||
if (result != 0) {
|
||||
warnln("pthread_rwlock_rdlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void RWLock::lock_write()
|
||||
{
|
||||
int result = pthread_rwlock_wrlock(to_impl(m_storage));
|
||||
if (result != 0) {
|
||||
warnln("pthread_rwlock_wrlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void RWLock::unlock_read()
|
||||
{
|
||||
int result = pthread_rwlock_unlock(to_impl(m_storage));
|
||||
if (result != 0) {
|
||||
warnln("pthread_rwlock_unlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void RWLock::unlock_write()
|
||||
{
|
||||
int result = pthread_rwlock_unlock(to_impl(m_storage));
|
||||
if (result != 0) {
|
||||
warnln("pthread_rwlock_unlock failed with: {}", Error::from_errno(result));
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
65
Libraries/LibSync/RWLockWindows.cpp
Normal file
65
Libraries/LibSync/RWLockWindows.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Ryszard Goc <ryszardgoc@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/Windows.h>
|
||||
#include <LibSync/Export.h>
|
||||
#include <LibSync/RWLock.h>
|
||||
|
||||
namespace Sync {
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE PSRWLOCK to_impl(void* ptr)
|
||||
{
|
||||
return reinterpret_cast<PSRWLOCK>(ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RWLock::RWLock()
|
||||
{
|
||||
static_assert(sizeof(SRWLOCK) == sizeof(m_storage));
|
||||
PSRWLOCK rwlock_ptr = new (m_storage) SRWLOCK;
|
||||
InitializeSRWLock(rwlock_ptr);
|
||||
}
|
||||
|
||||
RWLock::~RWLock() = default;
|
||||
|
||||
bool RWLock::try_lock_read()
|
||||
{
|
||||
return TryAcquireSRWLockShared(to_impl(m_storage));
|
||||
}
|
||||
|
||||
bool RWLock::try_lock_write()
|
||||
{
|
||||
return TryAcquireSRWLockExclusive(to_impl(m_storage));
|
||||
}
|
||||
|
||||
void RWLock::lock_read()
|
||||
{
|
||||
AcquireSRWLockShared(to_impl(m_storage));
|
||||
}
|
||||
|
||||
void RWLock::lock_write()
|
||||
{
|
||||
AcquireSRWLockExclusive(to_impl(m_storage));
|
||||
}
|
||||
|
||||
void RWLock::unlock_read()
|
||||
{
|
||||
ReleaseSRWLockShared(to_impl(m_storage));
|
||||
}
|
||||
|
||||
void RWLock::unlock_write()
|
||||
{
|
||||
ReleaseSRWLockExclusive(to_impl(m_storage));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue