mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1757100 - Move minimal platform-dependent part of RWLock to mozglue/misc/PlatformRWLock.h&cpp - r=glandium,xpcom-reviewers
This is consistent with how xpcom's Mutex has its platform-dependent code in mozglue, and will allow readers-writer locks in mozglue without duplication. Differential Revision: https://phabricator.services.mozilla.com/D139669
This commit is contained in:
parent
c05a6a04a8
commit
97bc60386d
50
mozglue/misc/PlatformRWLock.h
Normal file
50
mozglue/misc/PlatformRWLock.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_PlatformRWLock_h
|
||||
#define mozilla_PlatformRWLock_h
|
||||
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
#ifndef XP_WIN
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla::detail {
|
||||
|
||||
class RWLockImpl {
|
||||
public:
|
||||
explicit MFBT_API RWLockImpl();
|
||||
MFBT_API ~RWLockImpl();
|
||||
|
||||
protected:
|
||||
[[nodiscard]] MFBT_API bool tryReadLock();
|
||||
MFBT_API void readLock();
|
||||
MFBT_API void readUnlock();
|
||||
|
||||
[[nodiscard]] MFBT_API bool tryWriteLock();
|
||||
MFBT_API void writeLock();
|
||||
MFBT_API void writeUnlock();
|
||||
|
||||
private:
|
||||
RWLockImpl(const RWLockImpl&) = delete;
|
||||
void operator=(const RWLockImpl&) = delete;
|
||||
RWLockImpl(RWLockImpl&&) = delete;
|
||||
void operator=(RWLockImpl&&) = delete;
|
||||
bool operator==(const RWLockImpl& rhs) = delete;
|
||||
|
||||
#ifndef XP_WIN
|
||||
pthread_rwlock_t mRWLock;
|
||||
#else
|
||||
// SRWLock is pointer-sized. We declare it in such a fashion here to avoid
|
||||
// pulling in windows.h wherever this header is used.
|
||||
void* mRWLock;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla::detail
|
||||
|
||||
#endif // mozilla_PlatformRWLock_h
|
64
mozglue/misc/RWLock_posix.cpp
Normal file
64
mozglue/misc/RWLock_posix.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifdef XP_WIN
|
||||
# error This file should only be compiled on non-Windows platforms.
|
||||
#endif
|
||||
|
||||
#include "mozilla/PlatformRWLock.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
mozilla::detail::RWLockImpl::RWLockImpl() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_init(&mRWLock, nullptr) == 0,
|
||||
"pthread_rwlock_init failed");
|
||||
}
|
||||
|
||||
mozilla::detail::RWLockImpl::~RWLockImpl() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_destroy(&mRWLock) == 0,
|
||||
"pthread_rwlock_destroy failed");
|
||||
}
|
||||
|
||||
bool mozilla::detail::RWLockImpl::tryReadLock() {
|
||||
int rv = pthread_rwlock_tryrdlock(&mRWLock);
|
||||
// We allow EDEADLK here because it has been observed returned on macos when
|
||||
// the write lock is held by the current thread.
|
||||
MOZ_RELEASE_ASSERT(rv == 0 || rv == EBUSY || rv == EDEADLK,
|
||||
"pthread_rwlock_tryrdlock failed");
|
||||
return rv == 0;
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::readLock() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_rdlock(&mRWLock) == 0,
|
||||
"pthread_rwlock_rdlock failed");
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::readUnlock() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_unlock(&mRWLock) == 0,
|
||||
"pthread_rwlock_unlock failed");
|
||||
}
|
||||
|
||||
bool mozilla::detail::RWLockImpl::tryWriteLock() {
|
||||
int rv = pthread_rwlock_trywrlock(&mRWLock);
|
||||
// We allow EDEADLK here because it has been observed returned on macos when
|
||||
// the write lock is held by the current thread.
|
||||
MOZ_RELEASE_ASSERT(rv == 0 || rv == EBUSY || rv == EDEADLK,
|
||||
"pthread_rwlock_trywrlock failed");
|
||||
return rv == 0;
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::writeLock() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_wrlock(&mRWLock) == 0,
|
||||
"pthread_rwlock_wrlock failed");
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::writeUnlock() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_unlock(&mRWLock) == 0,
|
||||
"pthread_rwlock_unlock failed");
|
||||
}
|
48
mozglue/misc/RWLock_windows.cpp
Normal file
48
mozglue/misc/RWLock_windows.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef XP_WIN
|
||||
# error This file should only be compiled on Windows.
|
||||
#endif
|
||||
|
||||
#include "mozilla/PlatformRWLock.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define NativeHandle(m) (reinterpret_cast<SRWLOCK*>(&m))
|
||||
|
||||
mozilla::detail::RWLockImpl::RWLockImpl() {
|
||||
static_assert(sizeof(SRWLOCK) <= sizeof(mRWLock), "SRWLOCK is too big!");
|
||||
InitializeSRWLock(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
mozilla::detail::RWLockImpl::~RWLockImpl() {}
|
||||
|
||||
bool mozilla::detail::RWLockImpl::tryReadLock() {
|
||||
return TryAcquireSRWLockShared(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::readLock() {
|
||||
AcquireSRWLockShared(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::readUnlock() {
|
||||
ReleaseSRWLockShared(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
bool mozilla::detail::RWLockImpl::tryWriteLock() {
|
||||
return TryAcquireSRWLockExclusive(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::writeLock() {
|
||||
AcquireSRWLockExclusive(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
void mozilla::detail::RWLockImpl::writeUnlock() {
|
||||
ReleaseSRWLockExclusive(NativeHandle(mRWLock));
|
||||
}
|
||||
|
||||
#undef NativeHandle
|
@ -15,6 +15,7 @@ EXPORTS.mozilla += [
|
||||
"MmapFaultHandler.h",
|
||||
"PlatformConditionVariable.h",
|
||||
"PlatformMutex.h",
|
||||
"PlatformRWLock.h",
|
||||
"Printf.h",
|
||||
"Sprintf.h",
|
||||
"StackWalk.h",
|
||||
@ -105,6 +106,7 @@ if CONFIG["OS_ARCH"] == "WINNT":
|
||||
SOURCES += [
|
||||
"ConditionVariable_windows.cpp",
|
||||
"Mutex_windows.cpp",
|
||||
"RWLock_windows.cpp",
|
||||
]
|
||||
# WASI hasn't supported cond vars and mutexes yet so noop implementation is used.
|
||||
elif CONFIG["OS_ARCH"] == "WASI":
|
||||
@ -116,6 +118,7 @@ else:
|
||||
SOURCES += [
|
||||
"ConditionVariable_posix.cpp",
|
||||
"Mutex_posix.cpp",
|
||||
"RWLock_posix.cpp",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_LINKER"] and CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
|
||||
|
@ -337,7 +337,7 @@ void OffTheBooksMutex::AssertCurrentThreadOwns() const {
|
||||
//
|
||||
|
||||
bool RWLock::TryReadLock() {
|
||||
bool locked = this->TryReadLockInternal();
|
||||
bool locked = this->detail::RWLockImpl::tryReadLock();
|
||||
MOZ_ASSERT_IF(locked, mOwningThread == nullptr);
|
||||
return locked;
|
||||
}
|
||||
@ -346,17 +346,17 @@ void RWLock::ReadLock() {
|
||||
// All we want to ensure here is that we're not attempting to acquire the
|
||||
// read lock while this thread is holding the write lock.
|
||||
CheckAcquire();
|
||||
this->ReadLockInternal();
|
||||
this->detail::RWLockImpl::readLock();
|
||||
MOZ_ASSERT(mOwningThread == nullptr);
|
||||
}
|
||||
|
||||
void RWLock::ReadUnlock() {
|
||||
MOZ_ASSERT(mOwningThread == nullptr);
|
||||
this->ReadUnlockInternal();
|
||||
this->detail::RWLockImpl::readUnlock();
|
||||
}
|
||||
|
||||
bool RWLock::TryWriteLock() {
|
||||
bool locked = this->TryWriteLockInternal();
|
||||
bool locked = this->detail::RWLockImpl::tryWriteLock();
|
||||
if (locked) {
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
Acquire();
|
||||
@ -366,7 +366,7 @@ bool RWLock::TryWriteLock() {
|
||||
|
||||
void RWLock::WriteLock() {
|
||||
CheckAcquire();
|
||||
this->WriteLockInternal();
|
||||
this->detail::RWLockImpl::writeLock();
|
||||
mOwningThread = PR_GetCurrentThread();
|
||||
Acquire();
|
||||
}
|
||||
@ -374,7 +374,7 @@ void RWLock::WriteLock() {
|
||||
void RWLock::WriteUnlock() {
|
||||
Release();
|
||||
mOwningThread = nullptr;
|
||||
this->WriteUnlockInternal();
|
||||
this->detail::RWLockImpl::writeUnlock();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -6,16 +6,6 @@
|
||||
|
||||
#include "mozilla/RWLock.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
# include <windows.h>
|
||||
|
||||
static_assert(sizeof(SRWLOCK) <= sizeof(void*), "SRWLOCK is too big!");
|
||||
|
||||
# define NativeHandle(m) (reinterpret_cast<SRWLOCK*>(&m))
|
||||
#else
|
||||
# define NativeHandle(m) (&m)
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
RWLock::RWLock(const char* aName)
|
||||
@ -25,12 +15,6 @@ RWLock::RWLock(const char* aName)
|
||||
mOwningThread(nullptr)
|
||||
#endif
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
InitializeSRWLock(NativeHandle(mRWLock));
|
||||
#else
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_init(NativeHandle(mRWLock), nullptr) == 0,
|
||||
"pthread_rwlock_init failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -39,75 +23,6 @@ bool RWLock::LockedForWritingByCurrentThread() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef XP_WIN
|
||||
RWLock::~RWLock() {
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_destroy(NativeHandle(mRWLock)) == 0,
|
||||
"pthread_rwlock_destroy failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
bool RWLock::TryReadLockInternal() {
|
||||
#ifdef XP_WIN
|
||||
return TryAcquireSRWLockShared(NativeHandle(mRWLock));
|
||||
#else
|
||||
int rv = pthread_rwlock_tryrdlock(NativeHandle(mRWLock));
|
||||
// We allow EDEADLK here because it has been observed returned on macos when
|
||||
// the write lock is held by the current thread.
|
||||
MOZ_RELEASE_ASSERT(rv == 0 || rv == EBUSY || rv == EDEADLK,
|
||||
"pthread_rwlock_tryrdlock failed");
|
||||
return rv == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RWLock::ReadLockInternal() {
|
||||
#ifdef XP_WIN
|
||||
AcquireSRWLockShared(NativeHandle(mRWLock));
|
||||
#else
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_rdlock(NativeHandle(mRWLock)) == 0,
|
||||
"pthread_rwlock_rdlock failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
void RWLock::ReadUnlockInternal() {
|
||||
#ifdef XP_WIN
|
||||
ReleaseSRWLockShared(NativeHandle(mRWLock));
|
||||
#else
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_unlock(NativeHandle(mRWLock)) == 0,
|
||||
"pthread_rwlock_unlock failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool RWLock::TryWriteLockInternal() {
|
||||
#ifdef XP_WIN
|
||||
return TryAcquireSRWLockExclusive(NativeHandle(mRWLock));
|
||||
#else
|
||||
int rv = pthread_rwlock_trywrlock(NativeHandle(mRWLock));
|
||||
// We allow EDEADLK here because it has been observed returned on macos when
|
||||
// the write lock is held by the current thread.
|
||||
MOZ_RELEASE_ASSERT(rv == 0 || rv == EBUSY || rv == EDEADLK,
|
||||
"pthread_rwlock_trywrlock failed");
|
||||
return rv == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RWLock::WriteLockInternal() {
|
||||
#ifdef XP_WIN
|
||||
AcquireSRWLockExclusive(NativeHandle(mRWLock));
|
||||
#else
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_wrlock(NativeHandle(mRWLock)) == 0,
|
||||
"pthread_rwlock_wrlock failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
void RWLock::WriteUnlockInternal() {
|
||||
#ifdef XP_WIN
|
||||
ReleaseSRWLockExclusive(NativeHandle(mRWLock));
|
||||
#else
|
||||
MOZ_RELEASE_ASSERT(pthread_rwlock_unlock(NativeHandle(mRWLock)) == 0,
|
||||
"pthread_rwlock_unlock failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#undef NativeHandle
|
||||
|
@ -12,10 +12,7 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/BlockingResourceBase.h"
|
||||
|
||||
#ifndef XP_WIN
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
#include "mozilla/PlatformRWLock.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -41,18 +38,10 @@ namespace mozilla {
|
||||
//
|
||||
// It is unspecified whether RWLock gives priority to waiting readers or
|
||||
// a waiting writer when unlocking.
|
||||
class RWLock : public BlockingResourceBase {
|
||||
class RWLock : public detail::RWLockImpl, public BlockingResourceBase {
|
||||
public:
|
||||
explicit RWLock(const char* aName);
|
||||
|
||||
// Windows rwlocks don't need any special handling to be destroyed, but
|
||||
// POSIX ones do.
|
||||
#ifdef XP_WIN
|
||||
~RWLock() = default;
|
||||
#else
|
||||
~RWLock();
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
bool LockedForWritingByCurrentThread();
|
||||
bool TryReadLock();
|
||||
@ -62,34 +51,19 @@ class RWLock : public BlockingResourceBase {
|
||||
void WriteLock();
|
||||
void WriteUnlock();
|
||||
#else
|
||||
bool TryReadLock() { return TryReadLockInternal(); }
|
||||
void ReadLock() { ReadLockInternal(); }
|
||||
void ReadUnlock() { ReadUnlockInternal(); }
|
||||
bool TryWriteLock() { return TryWriteLockInternal(); }
|
||||
void WriteLock() { WriteLockInternal(); }
|
||||
void WriteUnlock() { WriteUnlockInternal(); }
|
||||
bool TryReadLock() { return detail::RWLockImpl::tryReadLock(); }
|
||||
void ReadLock() { detail::RWLockImpl::readLock(); }
|
||||
void ReadUnlock() { detail::RWLockImpl::readUnlock(); }
|
||||
bool TryWriteLock() { return detail::RWLockImpl::tryWriteLock(); }
|
||||
void WriteLock() { detail::RWLockImpl::writeLock(); }
|
||||
void WriteUnlock() { detail::RWLockImpl::writeUnlock(); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool TryReadLockInternal();
|
||||
void ReadLockInternal();
|
||||
void ReadUnlockInternal();
|
||||
bool TryWriteLockInternal();
|
||||
void WriteLockInternal();
|
||||
void WriteUnlockInternal();
|
||||
|
||||
RWLock() = delete;
|
||||
RWLock(const RWLock&) = delete;
|
||||
RWLock& operator=(const RWLock&) = delete;
|
||||
|
||||
#ifndef XP_WIN
|
||||
pthread_rwlock_t mRWLock;
|
||||
#else
|
||||
// SRWLock is pointer-sized. We declare it in such a fashion here to
|
||||
// avoid pulling in windows.h wherever this header is used.
|
||||
void* mRWLock;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
// We record the owning thread for write locks only.
|
||||
PRThread* mOwningThread;
|
||||
|
Loading…
Reference in New Issue
Block a user