[*] RWLock: not implementing LockAbsMS and LockAbsNS can hurt the hotpath
This commit is contained in:
parent
d1b1bfb221
commit
68b4fe5f8b
@ -33,6 +33,33 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
}
|
||||
|
||||
template<bool bIsReadView, typename T>
|
||||
bool RWLockAccessView<bIsReadView, T>::LockAbsMS(AuUInt64 timeout)
|
||||
{
|
||||
|
||||
if constexpr (bIsReadView)
|
||||
{
|
||||
return ViewParent->LockReadNSAbs(AuMSToNS<AuUInt64>(timeout));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ViewParent->LockWriteNSAbs(AuMSToNS<AuUInt64>(timeout));
|
||||
}
|
||||
}
|
||||
|
||||
template<bool bIsReadView, typename T>
|
||||
bool RWLockAccessView<bIsReadView, T>::LockAbsNS(AuUInt64 timeout)
|
||||
{
|
||||
if constexpr (bIsReadView)
|
||||
{
|
||||
return ViewParent->LockReadNSAbs(timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ViewParent->LockWriteNSAbs(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool bIsReadView, typename T>
|
||||
bool RWLockAccessView<bIsReadView, T>::LockMS(AuUInt64 timeout)
|
||||
{
|
||||
@ -110,12 +137,60 @@ namespace Aurora::Threading::Primitives
|
||||
return this->conditionWriter_;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::LockReadNSAbs(AuUInt64 uTimeout)
|
||||
{
|
||||
if (this->TryLockReadNoSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AuInt32 iCurState {};
|
||||
do
|
||||
{
|
||||
iCurState = this->state_;
|
||||
|
||||
if (iCurState < 0)
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
|
||||
iCurState = this->state_;
|
||||
if (iCurState < 0)
|
||||
{
|
||||
AuInt64 iSecondTimeout {};
|
||||
|
||||
if (uTimeout)
|
||||
{
|
||||
iSecondTimeout = uTimeout - AuTime::SteadyClockNS();
|
||||
|
||||
if (iSecondTimeout <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR)
|
||||
if (!this->GetCondition().WaitForSignalNS(iSecondTimeout))
|
||||
#else
|
||||
if (!this->GetCondition().WaitForSignalNsEx(AuUnsafeRaiiToShared(&this->mutex_), iSecondTimeout))
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (iCurState < 0 ||
|
||||
AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) != iCurState);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::LockReadNS(AuUInt64 uTimeout)
|
||||
{
|
||||
if (this->state_ < 0 &&
|
||||
this->reentrantWriteLockHandle_ == GetThreadCookie())
|
||||
if (this->TryLockReadNoSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -134,22 +209,22 @@ namespace Aurora::Threading::Primitives
|
||||
iCurState = this->state_;
|
||||
if (iCurState < 0)
|
||||
{
|
||||
AuInt64 uSecondTimeout = 0;
|
||||
AuInt64 iSecondTimeout {};
|
||||
|
||||
if (uTimeout)
|
||||
{
|
||||
uSecondTimeout = uEndTime - AuTime::SteadyClockNS();
|
||||
iSecondTimeout = uEndTime - AuTime::SteadyClockNS();
|
||||
|
||||
if (uSecondTimeout <= 0)
|
||||
if (iSecondTimeout <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR)
|
||||
if (!this->GetCondition().WaitForSignalNS(uSecondTimeout))
|
||||
if (!this->GetCondition().WaitForSignalNS(iSecondTimeout))
|
||||
#else
|
||||
if (!this->GetCondition().WaitForSignalNsEx(AuUnsafeRaiiToShared(&this->mutex_), uSecondTimeout))
|
||||
if (!this->GetCondition().WaitForSignalNsEx(AuUnsafeRaiiToShared(&this->mutex_), iSecondTimeout))
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
@ -163,6 +238,85 @@ namespace Aurora::Threading::Primitives
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNSAbs(AuUInt64 uTimeout)
|
||||
{
|
||||
if constexpr (!bIsWriteRecursionAllowed)
|
||||
{
|
||||
if (TryLockWrite())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto uOld = this->state_;
|
||||
if (uOld < 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AuAtomicAdd(&this->writersPending_, 1);
|
||||
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (this->state_ != 0)
|
||||
{
|
||||
AuInt64 uSecondTimeout = 0;
|
||||
|
||||
if (uTimeout)
|
||||
{
|
||||
uSecondTimeout = uTimeout - AuTime::SteadyClockNS();
|
||||
|
||||
if (uSecondTimeout <= 0)
|
||||
{
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR)
|
||||
if (!this->GetConditionWriter().WaitForSignalNS(uSecondTimeout))
|
||||
#else
|
||||
if (!this->GetConditionWriter().WaitForSignalNsEx(AuUnsafeRaiiToShared(&this->mutex_), uSecondTimeout))
|
||||
#endif
|
||||
{
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (AuAtomicCompareExchange(&this->state_, -1, 0) == 0)
|
||||
{
|
||||
this->reentrantWriteLockHandle_ = GetThreadCookie();
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->GetConditionWriter().Broadcast();
|
||||
this->GetCondition().Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNS(AuUInt64 uTimeout)
|
||||
{
|
||||
@ -249,17 +403,23 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
return DoTryIf([=]()
|
||||
{
|
||||
auto iCurState = this->state_;
|
||||
|
||||
if (iCurState < 0)
|
||||
{
|
||||
return this->reentrantWriteLockHandle_ == GetThreadCookie();
|
||||
}
|
||||
|
||||
return AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) == iCurState;
|
||||
return TryLockReadNoSpin();
|
||||
});
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockReadNoSpin()
|
||||
{
|
||||
auto iCurState = this->state_;
|
||||
|
||||
if (iCurState < 0)
|
||||
{
|
||||
return this->reentrantWriteLockHandle_ == GetThreadCookie();
|
||||
}
|
||||
|
||||
return AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) == iCurState;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockWrite()
|
||||
{
|
||||
|
@ -29,6 +29,8 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
bool LockMS(AuUInt64 timeout) override;
|
||||
bool LockNS(AuUInt64 timeout) override;
|
||||
bool LockAbsMS(AuUInt64 timeout) override;
|
||||
bool LockAbsNS(AuUInt64 timeout) override;
|
||||
|
||||
bool TryLock() override;
|
||||
|
||||
@ -62,9 +64,12 @@ namespace Aurora::Threading::Primitives
|
||||
~RWLockImpl();
|
||||
|
||||
// i dont think i'll expose a high performance interface yet
|
||||
auline bool LockReadNSAbs(AuUInt64 timeout);// override;
|
||||
auline bool LockReadNS(AuUInt64 timeout);// override;
|
||||
auline bool LockWriteNS(AuUInt64 timeout);// override;
|
||||
auline bool LockWriteNSAbs(AuUInt64 timeout);// override;
|
||||
auline bool TryLockRead();// override;
|
||||
auline bool TryLockReadNoSpin();// override;
|
||||
auline bool TryLockWrite();// override;
|
||||
auline void UnlockRead();// override;
|
||||
auline void UnlockWrite();// override;
|
||||
|
Loading…
Reference in New Issue
Block a user