diff --git a/Include/Aurora/Runtime.hpp b/Include/Aurora/Runtime.hpp index ad281c5b..50e4a7f7 100644 --- a/Include/Aurora/Runtime.hpp +++ b/Include/Aurora/Runtime.hpp @@ -382,6 +382,8 @@ namespace Aurora AuUInt64 bWinXpThrough7BlazeOptimizerPower : 7 { 6 }; // dont worry about it. we dont care about old portables. lets try to make older win32 targets tweak the scheduling in our favor a bit. AuUInt64 bPreferLinuxPrimitivesFutexNoSpin : 1 { false }; AuUInt64 bPreferUnixPrimitivesNoSpin : 1 { false }; + AuUInt64 bAlwaysRWLockWriteBiasOnReadLock : 1 { false }; + AuUInt64 bEnableRWLockWriteBiasOnReadLock : 1 { true }; }; struct DummyConfig diff --git a/Source/Threading/Primitives/AuRWLock.cpp b/Source/Threading/Primitives/AuRWLock.cpp index ee39af00..2e3d95ce 100644 --- a/Source/Threading/Primitives/AuRWLock.cpp +++ b/Source/Threading/Primitives/AuRWLock.cpp @@ -208,11 +208,11 @@ namespace Aurora::Threading::Primitives return true; } - + template bool RWLockImpl::LockReadNS(AuUInt64 uTimeout) { - if (this->TryLockReadNoSpin()) + if (this->TryLockReadNoSpin()) { return true; } @@ -435,7 +435,7 @@ namespace Aurora::Threading::Primitives if (AuAtomicLoad(&this->state_) == 1 && AuAtomicLoad(&this->writersPending_) > 1) { - this->SignalManyWriter(); + this->SignalManyWriter(-1); } } @@ -479,7 +479,7 @@ namespace Aurora::Threading::Primitives if (AuAtomicLoad(&this->state_) == 1 && AuAtomicLoad(&this->writersPending_) > 1) { - this->SignalManyWriter(); + this->SignalManyWriter(-1); } } @@ -541,12 +541,12 @@ namespace Aurora::Threading::Primitives } template - void RWLockImpl::SignalManyWriter() + void RWLockImpl::SignalManyWriter(int iBias) { if (gUseFutexRWLock) { auto pThat = this->GetFutexConditionWriter(); - AuUInt32 uCount = AuAtomicLoad(&this->writersPending_); + AuUInt32 uCount = AuAtomicLoad(&this->writersPending_) + iBias; AuAtomicAdd(pThat, uCount); InternalLTSWakeCount(pThat, uCount); } @@ -563,16 +563,17 @@ namespace Aurora::Threading::Primitives { return DoTryIf([=]() { - return TryLockReadNoSpin(); + return TryLockReadNoSpin(); }); } else { - return TryLockReadNoSpin(); + return TryLockReadNoSpin(); } } template + template bool RWLockImpl::TryLockReadNoSpin() { auto iCurState = this->state_; @@ -582,6 +583,16 @@ namespace Aurora::Threading::Primitives return this->reentrantWriteLockHandle_ == GetThreadCookie(); } + if constexpr (CheckWrite) + { + if ((AuAtomicLoad(&this->writersPending_)) && + (iCurState > 0 || gRuntimeConfig.threadingConfig.bAlwaysRWLockWriteBiasOnReadLock) && + (gRuntimeConfig.threadingConfig.bEnableRWLockWriteBiasOnReadLock)) + { + return false; + } + } + return AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) == iCurState; } diff --git a/Source/Threading/Primitives/AuRWLock.hpp b/Source/Threading/Primitives/AuRWLock.hpp index 2c3471c0..08a5e057 100644 --- a/Source/Threading/Primitives/AuRWLock.hpp +++ b/Source/Threading/Primitives/AuRWLock.hpp @@ -69,7 +69,8 @@ namespace Aurora::Threading::Primitives auline bool LockWriteNS(AuUInt64 timeout);// override; auline bool LockWriteNSAbs(AuUInt64 timeout);// override; auline bool TryLockRead();// override; - auline bool TryLockReadNoSpin();// override; + template + auline bool TryLockReadNoSpin(); auline bool TryLockWrite();// override; auline void UnlockRead();// override; auline void UnlockWrite();// override; @@ -94,7 +95,7 @@ namespace Aurora::Threading::Primitives auline void SignalOneReader(); auline void SignalOneWriter(); auline void SignalManyReader(); - auline void SignalManyWriter(); + auline void SignalManyWriter(int iBias = 0); private: