From 7357764cfcb0b75ff3714eb744d8908dab80e903 Mon Sep 17 00:00:00 2001 From: J Reece Wilson Date: Mon, 18 Sep 2023 18:21:46 +0100 Subject: [PATCH] [*] Fix abnormal ::UnlockWrite performance under heavyweight native WaitOnAddress platforms (Linux, BSD-like, etc) --- Source/Threading/Primitives/AuRWLock.cpp | 76 +++++++++++++++--------- Source/Threading/Primitives/AuRWLock.hpp | 1 + 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/Source/Threading/Primitives/AuRWLock.cpp b/Source/Threading/Primitives/AuRWLock.cpp index 88e94c44..a4ebb80d 100644 --- a/Source/Threading/Primitives/AuRWLock.cpp +++ b/Source/Threading/Primitives/AuRWLock.cpp @@ -150,15 +150,25 @@ namespace Aurora::Threading::Primitives return (AuUInt32 *)this->conditionVariableWriter_; } + template + AuUInt32 *RWLockImpl::GetReadSleepCounter() + { + return (AuUInt32 *)this->conditionVariable_; + } + template bool RWLockImpl::LockReadNSAbs(AuUInt64 uTimeout) { + AuInt32 iCurState {}; + bool bRet {}; + if (this->TryLockRead()) { return true; } - AuInt32 iCurState {}; + auto pCounter = this->GetReadSleepCounter(); + do { iCurState = this->state_; @@ -167,7 +177,11 @@ namespace Aurora::Threading::Primitives { 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; } @@ -212,6 +226,9 @@ namespace Aurora::Threading::Primitives template bool RWLockImpl::LockReadNS(AuUInt64 uTimeout) { + AuInt32 iCurState {}; + bool bRet {}; + if (this->TryLockReadNoSpin()) { return true; @@ -224,7 +241,8 @@ namespace Aurora::Threading::Primitives return true; } - AuInt32 iCurState {}; + auto pCounter = this->GetReadSleepCounter(); + do { iCurState = this->state_; @@ -233,7 +251,11 @@ namespace Aurora::Threading::Primitives { 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; } @@ -331,15 +353,20 @@ namespace Aurora::Threading::Primitives bool RWLockImpl::LockWriteNSAbsSecondPath() { auto uOld = this->state_; - if (uOld < 0) + + if constexpr (bIsWriteRecursionAllowed) { - if (this->reentrantWriteLockHandle_ == GetThreadCookie()) + if (uOld < 0) { - AuAtomicSub(&this->state_, 1); - return true; + if (this->reentrantWriteLockHandle_ == GetThreadCookie()) + { + AuAtomicSub(&this->state_, 1); + return true; + } } } - else if (uOld == 0) + + if (uOld == 0) { if (AuAtomicCompareExchange(&this->state_, -1, uOld) == uOld) { @@ -354,6 +381,9 @@ namespace Aurora::Threading::Primitives template bool RWLockImpl::LockWriteNS(AuUInt64 uTimeout) { + bool bRet {}; + AuInt64 uEndTime {}; + if constexpr (!bIsWriteRecursionAllowed) { if (this->TryLockWrite()) @@ -363,27 +393,12 @@ namespace Aurora::Threading::Primitives } else { - auto uOld = AuAtomicLoad(&this->state_); - if (uOld < 0) + if (this->LockWriteNSAbsSecondPath()) { - if (this->reentrantWriteLockHandle_ == GetThreadCookie()) - { - AuAtomicSub(&this->state_, 1); - return true; - } - } - else if (uOld == 0) - { - if (AuAtomicCompareExchange(&this->state_, -1, uOld) == uOld) - { - this->reentrantWriteLockHandle_ = GetThreadCookie(); - return true; - } + return true; } } - bool bRet {}; - AuInt64 uEndTime {}; AuAtomicAdd(&this->writersPending_, 1); if (gUseFutexRWLock) @@ -411,17 +426,17 @@ namespace Aurora::Threading::Primitives { while (true) { + bool bStatus {}; AuInt32 iCurState; + while ((iCurState = AuAtomicLoad(&this->state_)) != 0) { AuInt64 uSecondTimeout = 0; - bool bStatus {}; if (gUseFutexRWLock) { auto pSemaphore = this->GetFutexConditionWriter(); - AuInt32 iCurState; while ((iCurState = AuAtomicLoad(&this->state_)) != 0) { static const AuUInt32 kExpect { 0 }; @@ -532,7 +547,10 @@ namespace Aurora::Threading::Primitives { if (gUseFutexRWLock) { - InternalLTSWakeAll((const void *)&this->state_); + if (AuAtomicLoad(this->GetReadSleepCounter())) + { + InternalLTSWakeAll((const void *)&this->state_); + } } else { diff --git a/Source/Threading/Primitives/AuRWLock.hpp b/Source/Threading/Primitives/AuRWLock.hpp index 08a5e057..0a92c161 100644 --- a/Source/Threading/Primitives/AuRWLock.hpp +++ b/Source/Threading/Primitives/AuRWLock.hpp @@ -97,6 +97,7 @@ namespace Aurora::Threading::Primitives auline void SignalManyReader(); auline void SignalManyWriter(int iBias = 0); + auline AuUInt32 *GetReadSleepCounter(); private: RWLockAccessView read_;