mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-12 09:56:45 +02:00
This commit adds in-place pimpl to abstract away the implementation of Mutex. It also adds policies to configure the type of mutex desired. Because of the tight integration between mutex and condition variables they also needed to be reworked and the changes have to be in one commit to retain atomicity. A win32 and pthread implemenation is provided to make sure the api works with both.
170 lines
4.4 KiB
C++
170 lines
4.4 KiB
C++
/*
|
|
* 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/Mutex.h>
|
|
|
|
namespace Sync {
|
|
|
|
template<>
|
|
Mutex::MutexBase()
|
|
{
|
|
static_assert(sizeof(m_storage) == sizeof(SRWLOCK));
|
|
PSRWLOCK pSRW = new (m_storage) SRWLOCK;
|
|
InitializeSRWLock(pSRW);
|
|
}
|
|
template<>
|
|
Mutex::~MutexBase() = default;
|
|
|
|
template<>
|
|
void Mutex::lock()
|
|
{
|
|
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(m_storage));
|
|
}
|
|
|
|
template<>
|
|
bool Mutex::try_lock()
|
|
{
|
|
return TryAcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(m_storage));
|
|
}
|
|
|
|
template<>
|
|
void Mutex::unlock()
|
|
{
|
|
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(m_storage));
|
|
}
|
|
|
|
template<>
|
|
RecursiveMutex::MutexBase()
|
|
{
|
|
static_assert(sizeof(m_storage) == sizeof(CRITICAL_SECTION));
|
|
LPCRITICAL_SECTION pCS = new (m_storage) CRITICAL_SECTION;
|
|
// TODO: Optimize this for our use case
|
|
InitializeCriticalSectionAndSpinCount(pCS, 4000);
|
|
}
|
|
|
|
template<>
|
|
RecursiveMutex::~MutexBase()
|
|
{
|
|
DeleteCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_storage));
|
|
}
|
|
|
|
template<>
|
|
void RecursiveMutex::lock()
|
|
{
|
|
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_storage));
|
|
}
|
|
|
|
template<>
|
|
bool RecursiveMutex::try_lock()
|
|
{
|
|
return TryEnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_storage));
|
|
}
|
|
|
|
template<>
|
|
void RecursiveMutex::unlock()
|
|
{
|
|
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(m_storage));
|
|
}
|
|
|
|
namespace {
|
|
|
|
void init_ipc_mutex(void* storage)
|
|
{
|
|
PHANDLE pHandle = new (storage) HANDLE;
|
|
SECURITY_ATTRIBUTES sa = { .nLength = sizeof(SECURITY_ATTRIBUTES), .lpSecurityDescriptor = nullptr, .bInheritHandle = TRUE };
|
|
// TODO: If we want to send these over IPC then some other methods have to be exposed to construct a MutexBase from
|
|
// the duplicated HANDLE. Otherwise it can use handle inheritance. We might want to only make it inheritable as an option.
|
|
HANDLE handle = CreateMutexW(&sa, FALSE, nullptr);
|
|
if (!handle) {
|
|
warnln("Failed to create mutex object with: {}", Error::from_windows_error());
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
*pHandle = handle;
|
|
}
|
|
|
|
void destroy_ipc_mutex(void* storage)
|
|
{
|
|
CloseHandle(*reinterpret_cast<PHANDLE>(storage));
|
|
}
|
|
|
|
void lock_ipc_mutex(void* storage)
|
|
{
|
|
DWORD result = WaitForSingleObject(*reinterpret_cast<PHANDLE>(storage), INFINITE);
|
|
if (result != WAIT_OBJECT_0) {
|
|
warnln("Failed to acquire mutex: {}", Error::from_windows_error(result));
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
}
|
|
|
|
bool try_lock_ipc_mutex(void* storage)
|
|
{
|
|
DWORD result = WaitForSingleObject(*reinterpret_cast<PHANDLE>(storage), 0);
|
|
if (result == WAIT_OBJECT_0) {
|
|
return true;
|
|
}
|
|
if (result == WAIT_TIMEOUT) {
|
|
return false;
|
|
}
|
|
if (result == WAIT_ABANDONED)
|
|
VERIFY_NOT_REACHED();
|
|
warnln("Failed trying to acquire mutex: {}", Error::from_windows_error(result));
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
|
|
void unlock_ipc_mutex(void* storage)
|
|
{
|
|
BOOL result = ReleaseMutex(*reinterpret_cast<PHANDLE>(storage));
|
|
if (!result) {
|
|
warnln("Failed to release mutex: {}", Error::from_windows_error());
|
|
VERIFY_NOT_REACHED();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
template<>
|
|
IPCMutex::MutexBase()
|
|
{
|
|
static_assert(sizeof(m_storage) == sizeof(HANDLE));
|
|
init_ipc_mutex(m_storage);
|
|
}
|
|
template<>
|
|
IPCMutex::~MutexBase() { destroy_ipc_mutex(m_storage); }
|
|
template<>
|
|
void IPCMutex::lock() { lock_ipc_mutex(m_storage); }
|
|
template<>
|
|
bool IPCMutex::try_lock() { return try_lock_ipc_mutex(m_storage); }
|
|
template<>
|
|
void IPCMutex::unlock() { unlock_ipc_mutex(m_storage); }
|
|
|
|
template<>
|
|
IPCRecursiveMutex::MutexBase()
|
|
{
|
|
static_assert(sizeof(m_storage) == sizeof(HANDLE));
|
|
init_ipc_mutex(m_storage);
|
|
}
|
|
template<>
|
|
IPCRecursiveMutex::~MutexBase() { destroy_ipc_mutex(m_storage); }
|
|
template<>
|
|
void IPCRecursiveMutex::lock() { lock_ipc_mutex(m_storage); }
|
|
template<>
|
|
bool IPCRecursiveMutex::try_lock() { return try_lock_ipc_mutex(m_storage); }
|
|
template<>
|
|
void IPCRecursiveMutex::unlock() { unlock_ipc_mutex(m_storage); }
|
|
|
|
template class SYNC_API MutexBase<PolicyNonRecursive, PolicyIntraprocess>;
|
|
template class SYNC_API MutexBase<PolicyRecursive, PolicyIntraprocess>;
|
|
template class SYNC_API MutexBase<PolicyNonRecursive, PolicyInterprocess>;
|
|
template class SYNC_API MutexBase<PolicyRecursive, PolicyInterprocess>;
|
|
|
|
}
|