[*] Fix abnormal ::UnlockWrite performance under heavyweight native WaitOnAddress platforms (Linux, BSD-like, etc)

This commit is contained in:
Reece Wilson 2023-09-18 18:21:46 +01:00
parent 5d12f1a203
commit 7357764cfc
2 changed files with 48 additions and 29 deletions

View File

@ -150,15 +150,25 @@ namespace Aurora::Threading::Primitives
return (AuUInt32 *)this->conditionVariableWriter_; return (AuUInt32 *)this->conditionVariableWriter_;
} }
template<bool bIsWriteRecursionAllowed>
AuUInt32 *RWLockImpl<bIsWriteRecursionAllowed>::GetReadSleepCounter()
{
return (AuUInt32 *)this->conditionVariable_;
}
template<bool bIsWriteRecursionAllowed> template<bool bIsWriteRecursionAllowed>
bool RWLockImpl<bIsWriteRecursionAllowed>::LockReadNSAbs(AuUInt64 uTimeout) bool RWLockImpl<bIsWriteRecursionAllowed>::LockReadNSAbs(AuUInt64 uTimeout)
{ {
AuInt32 iCurState {};
bool bRet {};
if (this->TryLockRead()) if (this->TryLockRead())
{ {
return true; return true;
} }
AuInt32 iCurState {}; auto pCounter = this->GetReadSleepCounter();
do do
{ {
iCurState = this->state_; iCurState = this->state_;
@ -167,7 +177,11 @@ namespace Aurora::Threading::Primitives
{ {
if (gUseFutexRWLock) if (gUseFutexRWLock)
{ {
if (!InternalLTSWaitOnAddressHighRes((const void *)&this->state_, &iCurState, sizeof(iCurState), uTimeout)) AuAtomicAdd(pCounter, 1u);
bRet = InternalLTSWaitOnAddressHighRes((const void *)&this->state_, &iCurState, sizeof(iCurState), uTimeout);
AuAtomicSub(pCounter, 1u);
if (!bRet)
{ {
return false; return false;
} }
@ -212,6 +226,9 @@ namespace Aurora::Threading::Primitives
template<bool bIsWriteRecursionAllowed> template<bool bIsWriteRecursionAllowed>
bool RWLockImpl<bIsWriteRecursionAllowed>::LockReadNS(AuUInt64 uTimeout) bool RWLockImpl<bIsWriteRecursionAllowed>::LockReadNS(AuUInt64 uTimeout)
{ {
AuInt32 iCurState {};
bool bRet {};
if (this->TryLockReadNoSpin<true>()) if (this->TryLockReadNoSpin<true>())
{ {
return true; return true;
@ -224,7 +241,8 @@ namespace Aurora::Threading::Primitives
return true; return true;
} }
AuInt32 iCurState {}; auto pCounter = this->GetReadSleepCounter();
do do
{ {
iCurState = this->state_; iCurState = this->state_;
@ -233,7 +251,11 @@ namespace Aurora::Threading::Primitives
{ {
if (gUseFutexRWLock) if (gUseFutexRWLock)
{ {
if (!InternalLTSWaitOnAddressHighRes((const void *)&this->state_, &iCurState, sizeof(iCurState), uEndTime)) AuAtomicAdd(pCounter, 1u);
bRet = InternalLTSWaitOnAddressHighRes((const void *)&this->state_, &iCurState, sizeof(iCurState), uEndTime);
AuAtomicSub(pCounter, 1u);
if (!bRet)
{ {
return false; return false;
} }
@ -331,6 +353,9 @@ namespace Aurora::Threading::Primitives
bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNSAbsSecondPath() bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNSAbsSecondPath()
{ {
auto uOld = this->state_; auto uOld = this->state_;
if constexpr (bIsWriteRecursionAllowed)
{
if (uOld < 0) if (uOld < 0)
{ {
if (this->reentrantWriteLockHandle_ == GetThreadCookie()) if (this->reentrantWriteLockHandle_ == GetThreadCookie())
@ -339,7 +364,9 @@ namespace Aurora::Threading::Primitives
return true; return true;
} }
} }
else if (uOld == 0) }
if (uOld == 0)
{ {
if (AuAtomicCompareExchange(&this->state_, -1, uOld) == uOld) if (AuAtomicCompareExchange(&this->state_, -1, uOld) == uOld)
{ {
@ -354,6 +381,9 @@ namespace Aurora::Threading::Primitives
template<bool bIsWriteRecursionAllowed> template<bool bIsWriteRecursionAllowed>
bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNS(AuUInt64 uTimeout) bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNS(AuUInt64 uTimeout)
{ {
bool bRet {};
AuInt64 uEndTime {};
if constexpr (!bIsWriteRecursionAllowed) if constexpr (!bIsWriteRecursionAllowed)
{ {
if (this->TryLockWrite()) if (this->TryLockWrite())
@ -363,27 +393,12 @@ namespace Aurora::Threading::Primitives
} }
else else
{ {
auto uOld = AuAtomicLoad(&this->state_); if (this->LockWriteNSAbsSecondPath())
if (uOld < 0)
{ {
if (this->reentrantWriteLockHandle_ == GetThreadCookie())
{
AuAtomicSub(&this->state_, 1);
return true; return true;
} }
} }
else if (uOld == 0)
{
if (AuAtomicCompareExchange(&this->state_, -1, uOld) == uOld)
{
this->reentrantWriteLockHandle_ = GetThreadCookie();
return true;
}
}
}
bool bRet {};
AuInt64 uEndTime {};
AuAtomicAdd(&this->writersPending_, 1); AuAtomicAdd(&this->writersPending_, 1);
if (gUseFutexRWLock) if (gUseFutexRWLock)
@ -411,17 +426,17 @@ namespace Aurora::Threading::Primitives
{ {
while (true) while (true)
{ {
bool bStatus {};
AuInt32 iCurState; AuInt32 iCurState;
while ((iCurState = AuAtomicLoad(&this->state_)) != 0) while ((iCurState = AuAtomicLoad(&this->state_)) != 0)
{ {
AuInt64 uSecondTimeout = 0; AuInt64 uSecondTimeout = 0;
bool bStatus {};
if (gUseFutexRWLock) if (gUseFutexRWLock)
{ {
auto pSemaphore = this->GetFutexConditionWriter(); auto pSemaphore = this->GetFutexConditionWriter();
AuInt32 iCurState;
while ((iCurState = AuAtomicLoad(&this->state_)) != 0) while ((iCurState = AuAtomicLoad(&this->state_)) != 0)
{ {
static const AuUInt32 kExpect { 0 }; static const AuUInt32 kExpect { 0 };
@ -531,9 +546,12 @@ namespace Aurora::Threading::Primitives
void RWLockImpl<bIsWriteRecursionAllowed>::SignalManyReader() void RWLockImpl<bIsWriteRecursionAllowed>::SignalManyReader()
{ {
if (gUseFutexRWLock) if (gUseFutexRWLock)
{
if (AuAtomicLoad(this->GetReadSleepCounter()))
{ {
InternalLTSWakeAll((const void *)&this->state_); InternalLTSWakeAll((const void *)&this->state_);
} }
}
else else
{ {
this->GetCondition().Broadcast(); this->GetCondition().Broadcast();

View File

@ -97,6 +97,7 @@ namespace Aurora::Threading::Primitives
auline void SignalManyReader(); auline void SignalManyReader();
auline void SignalManyWriter(int iBias = 0); auline void SignalManyWriter(int iBias = 0);
auline AuUInt32 *GetReadSleepCounter();
private: private:
RWLockAccessView<true, RWLockImpl> read_; RWLockAccessView<true, RWLockImpl> read_;