[*] Clean up RWLock
This commit is contained in:
parent
baadcbb13d
commit
9e1655d579
@ -19,6 +19,10 @@ namespace Aurora::Threading::Primitives
|
||||
#define ViewParent ((T *)(((char *)this) - (bIsReadView ? RWLockImpl<true>::kOffsetOfRead : RWLockImpl<true>::kOffsetOfWrite)))
|
||||
#endif
|
||||
|
||||
#define RWLockAcquire AU_LOCK_GUARD(this->mutex_);
|
||||
#define RWLockBarrier(expMutex) { (expMutex).Lock(); (expMutex).Unlock(); }
|
||||
#define RWLockBarrierSelf() RWLockBarrier(this->mutex_)
|
||||
|
||||
static const auto kRWThreadWriterHardContextSwitchBias = 15;
|
||||
|
||||
template<bool bIsReadView, typename T>
|
||||
@ -95,7 +99,7 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
else
|
||||
{
|
||||
return ViewParent->TryLockWrite();
|
||||
return ViewParent->TryLockWriteMaybeSpin();
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,7 +145,7 @@ namespace Aurora::Threading::Primitives
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
AuUInt32 *RWLockImpl<bIsWriteRecursionAllowed>::GetFutexCondition()
|
||||
{
|
||||
return (AuUInt32 *)&this->state_;
|
||||
return (AuUInt32 *)&this->iState_;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
@ -171,14 +175,14 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
do
|
||||
{
|
||||
iCurState = this->state_;
|
||||
iCurState = this->iState_;
|
||||
|
||||
if (iCurState < 0)
|
||||
{
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
AuAtomicAdd(pCounter, 1u);
|
||||
bRet = InternalLTSWaitOnAddressHighRes((const void *)&this->state_, &iCurState, sizeof(iCurState), uTimeout);
|
||||
bRet = InternalLTSWaitOnAddressHighRes((const void *)&this->iState_, &iCurState, sizeof(iCurState), uTimeout);
|
||||
AuAtomicSub(pCounter, 1u);
|
||||
|
||||
if (!bRet)
|
||||
@ -188,9 +192,9 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
else
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
RWLockAcquire;
|
||||
|
||||
iCurState = this->state_;
|
||||
iCurState = this->iState_;
|
||||
if (iCurState < 0)
|
||||
{
|
||||
AuInt64 iSecondTimeout {};
|
||||
@ -218,7 +222,7 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
}
|
||||
while (iCurState < 0 ||
|
||||
AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) != iCurState);
|
||||
AuAtomicCompareExchange(&this->iState_, iCurState + 1, iCurState) != iCurState);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -245,14 +249,14 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
do
|
||||
{
|
||||
iCurState = this->state_;
|
||||
iCurState = this->iState_;
|
||||
|
||||
if (iCurState < 0)
|
||||
{
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
AuAtomicAdd(pCounter, 1u);
|
||||
bRet = InternalLTSWaitOnAddressHighRes((const void *)&this->state_, &iCurState, sizeof(iCurState), uEndTime);
|
||||
bRet = InternalLTSWaitOnAddressHighRes((const void *)&this->iState_, &iCurState, sizeof(iCurState), uEndTime);
|
||||
AuAtomicSub(pCounter, 1u);
|
||||
|
||||
if (!bRet)
|
||||
@ -262,9 +266,9 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
else
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
RWLockAcquire;
|
||||
|
||||
iCurState = this->state_;
|
||||
iCurState = this->iState_;
|
||||
if (iCurState < 0)
|
||||
{
|
||||
AuInt64 iSecondTimeout {};
|
||||
@ -292,11 +296,35 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
}
|
||||
while (iCurState < 0 ||
|
||||
AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) != iCurState);
|
||||
AuAtomicCompareExchange(&this->iState_, iCurState + 1, iCurState) != iCurState);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockWriteMaybeSpin()
|
||||
{
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
if (DoTryIf([=]()
|
||||
{
|
||||
return this->TryLockWriteNoSpin();
|
||||
}))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->TryLockWriteNoSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNSAbs(AuUInt64 uTimeout)
|
||||
{
|
||||
@ -304,33 +332,20 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if constexpr (!bIsWriteRecursionAllowed)
|
||||
{
|
||||
if (this->TryLockWrite())
|
||||
if (this->TryLockWriteScatterSwitch())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gUseFutexRWLock)
|
||||
if (this->TryLockWriteMaybeSpin())
|
||||
{
|
||||
if (DoTryIf([=]()
|
||||
{
|
||||
return this->LockWriteNSAbsSecondPath();
|
||||
}))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->LockWriteNSAbsSecondPath())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AuAtomicAdd(&this->writersPending_, 1);
|
||||
AuAtomicAdd(&this->dwWritersPending_, 1);
|
||||
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
@ -338,21 +353,20 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
else
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
RWLockAcquire;
|
||||
|
||||
bRet = this->LockWriteNSAbsUnlocked(uTimeout);
|
||||
}
|
||||
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
AuAtomicSub(&this->dwWritersPending_, 1);
|
||||
|
||||
return bRet;
|
||||
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::LockWriteNSAbsSecondPath()
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockWriteNoSpin()
|
||||
{
|
||||
auto uOld = this->state_;
|
||||
auto uOld = this->iState_;
|
||||
|
||||
if constexpr (bIsWriteRecursionAllowed)
|
||||
{
|
||||
@ -360,7 +374,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
if (this->reentrantWriteLockHandle_ == GetThreadCookie())
|
||||
{
|
||||
AuAtomicSub(&this->state_, 1);
|
||||
AuAtomicSub(&this->iState_, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -368,7 +382,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (uOld == 0)
|
||||
{
|
||||
if (AuAtomicCompareExchange(&this->state_, -1, uOld) == uOld)
|
||||
if (AuAtomicCompareExchange(&this->iState_, -1, uOld) == uOld)
|
||||
{
|
||||
this->reentrantWriteLockHandle_ = GetThreadCookie();
|
||||
return true;
|
||||
@ -386,20 +400,20 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if constexpr (!bIsWriteRecursionAllowed)
|
||||
{
|
||||
if (this->TryLockWrite())
|
||||
if (this->TryLockWriteScatterSwitch())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->LockWriteNSAbsSecondPath())
|
||||
if (this->TryLockWriteMaybeSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AuAtomicAdd(&this->writersPending_, 1);
|
||||
AuAtomicAdd(&this->dwWritersPending_, 1);
|
||||
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
@ -411,12 +425,12 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
uEndTime = uTimeout ? AuTime::SteadyClockNS() + uTimeout : 0;
|
||||
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
RWLockAcquire;
|
||||
|
||||
bRet = this->LockWriteNSAbsUnlocked(uEndTime);
|
||||
}
|
||||
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
AuAtomicSub(&this->dwWritersPending_, 1);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
@ -426,100 +440,129 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool bStatus {};
|
||||
AuInt32 iCurState;
|
||||
|
||||
while ((iCurState = AuAtomicLoad(&this->state_)) != 0)
|
||||
if (this->WriterSleep(qwTimeoutNS))
|
||||
{
|
||||
AuInt64 uSecondTimeout = 0;
|
||||
|
||||
if (gUseFutexRWLock)
|
||||
if (this->WriterTryLock())
|
||||
{
|
||||
auto pSemaphore = this->GetFutexConditionWriter();
|
||||
|
||||
while ((iCurState = AuAtomicLoad(&this->state_)) != 0)
|
||||
{
|
||||
static const AuUInt32 kExpect { 0 };
|
||||
if (!InternalLTSWaitOnAddressHighRes(pSemaphore, &kExpect, sizeof(kExpect), qwTimeoutNS))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if constexpr (bIsWriteRecursionAllowed)
|
||||
{
|
||||
if (AuAtomicLoad(&this->state_) == 1 &&
|
||||
AuAtomicLoad(&this->writersPending_) > 1)
|
||||
{
|
||||
this->SignalManyWriter(-1);
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto uState = *pSemaphore;
|
||||
|
||||
if (uState == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (AuAtomicCompareExchange(pSemaphore, uState - 1, uState) == uState)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qwTimeoutNS)
|
||||
{
|
||||
uSecondTimeout = qwTimeoutNS - AuTime::SteadyClockNS();
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->WriterTryLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uSecondTimeout <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
void RWLockImpl<bIsWriteRecursionAllowed>::FutexWriterWake()
|
||||
{
|
||||
auto pSemaphore = this->GetFutexConditionWriter();
|
||||
while (true)
|
||||
{
|
||||
auto uState = *pSemaphore;
|
||||
|
||||
#if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR)
|
||||
bStatus = this->GetConditionWriter().WaitForSignalNS(uSecondTimeout);
|
||||
#else
|
||||
bStatus = this->GetConditionWriter().WaitForSignalNsEx(&this->mutex_, uSecondTimeout);
|
||||
#endif
|
||||
}
|
||||
if (uState == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if constexpr (bIsWriteRecursionAllowed)
|
||||
{
|
||||
if (AuAtomicLoad(&this->state_) == 1 &&
|
||||
AuAtomicLoad(&this->writersPending_) > 1)
|
||||
{
|
||||
this->SignalManyWriter(-1);
|
||||
}
|
||||
}
|
||||
if (AuAtomicCompareExchange(pSemaphore, uState - 1, uState) == uState)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::WriterTryLock()
|
||||
{
|
||||
if (AuAtomicCompareExchange(&this->iState_, -1, 0) == 0)
|
||||
{
|
||||
this->reentrantWriteLockHandle_ = GetThreadCookie();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::WriterSleep(AuUInt64 qwTimeoutNS)
|
||||
{
|
||||
bool bStatus { true };
|
||||
AuInt32 iCurState;
|
||||
|
||||
auto pSemaphore = this->GetFutexConditionWriter();
|
||||
|
||||
while ((iCurState = AuAtomicLoad(&this->iState_)) != 0)
|
||||
{
|
||||
AuInt64 uSecondTimeout = 0;
|
||||
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
static const AuUInt32 kExpect { 0 };
|
||||
|
||||
bStatus = InternalLTSWaitOnAddressHighRes(pSemaphore, &kExpect, sizeof(kExpect), qwTimeoutNS);
|
||||
|
||||
this->WriterWake();
|
||||
|
||||
if (!bStatus)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (AuAtomicCompareExchange(&this->state_, -1, 0) == 0)
|
||||
this->FutexWriterWake();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->reentrantWriteLockHandle_ = GetThreadCookie();
|
||||
return true;
|
||||
if (qwTimeoutNS)
|
||||
{
|
||||
uSecondTimeout = qwTimeoutNS - AuTime::SteadyClockNS();
|
||||
|
||||
if (uSecondTimeout <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AURWLOCK_NO_SIZE_OPTIMIZED_CONDVAR)
|
||||
bStatus = this->GetConditionWriter().WaitForSignalNS(uSecondTimeout);
|
||||
#else
|
||||
bStatus = this->GetConditionWriter().WaitForSignalNsEx(&this->mutex_, uSecondTimeout);
|
||||
#endif
|
||||
|
||||
this->WriterWake();
|
||||
|
||||
if (!bStatus)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
void RWLockImpl<bIsWriteRecursionAllowed>::WriterWake()
|
||||
{
|
||||
if (AuAtomicLoad(&this->iState_) == 1 &&
|
||||
AuAtomicLoad(&this->dwWritersPending_) > 1)
|
||||
{
|
||||
this->SignalManyWriter(-1);
|
||||
}
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
void RWLockImpl<bIsWriteRecursionAllowed>::SignalOneReader()
|
||||
{
|
||||
// Unused method!
|
||||
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
InternalLTSWakeOne((const void *)&this->state_);
|
||||
InternalLTSWakeOne((const void *)&this->iState_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -534,10 +577,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
auto pThat = this->GetFutexConditionWriter();
|
||||
AuAtomicAdd(pThat, 1u);
|
||||
if (AuAtomicLoad(&this->writersPending_))
|
||||
{
|
||||
InternalLTSWakeOne(pThat);
|
||||
}
|
||||
InternalLTSWakeOne(pThat); // Note: all paths check for a waiter ahead of time!
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -552,7 +592,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
if (AuAtomicLoad(this->GetReadSleepCounter()))
|
||||
{
|
||||
InternalLTSWakeAll((const void *)&this->state_);
|
||||
InternalLTSWakeAll((const void *)&this->iState_);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -567,7 +607,7 @@ namespace Aurora::Threading::Primitives
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
auto pThat = this->GetFutexConditionWriter();
|
||||
if (auto uCount = AuUInt32(AuAtomicLoad(&this->writersPending_) + iBias))
|
||||
if (auto uCount = AuUInt32(AuAtomicLoad(&this->dwWritersPending_) + iBias))
|
||||
{
|
||||
AuAtomicAdd(pThat, uCount);
|
||||
InternalLTSWakeCount(pThat, uCount);
|
||||
@ -583,7 +623,7 @@ namespace Aurora::Threading::Primitives
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockRead()
|
||||
{
|
||||
if (ThrdCfg::gPreferRWLockReadLockSpin &&
|
||||
AuAtomicLoad(&this->writersPending_) == 0)
|
||||
AuAtomicLoad(&this->dwWritersPending_) == 0)
|
||||
{
|
||||
return DoTryIf([=]()
|
||||
{
|
||||
@ -597,19 +637,19 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
template<bool CheckWrite>
|
||||
template<bool bCheckWrite>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockReadNoSpin()
|
||||
{
|
||||
auto iCurState = this->state_;
|
||||
auto iCurState = this->iState_;
|
||||
|
||||
if (iCurState < 0)
|
||||
{
|
||||
return this->reentrantWriteLockHandle_ == GetThreadCookie();
|
||||
}
|
||||
|
||||
if constexpr (CheckWrite)
|
||||
if constexpr (bCheckWrite)
|
||||
{
|
||||
if ((AuAtomicLoad(&this->writersPending_)) &&
|
||||
if ((AuAtomicLoad(&this->dwWritersPending_)) &&
|
||||
(iCurState > 0 || ThrdCfg::gAlwaysRWLockWriteBiasOnReadLock) &&
|
||||
(ThrdCfg::gEnableRWLockWriteBiasOnReadLock))
|
||||
{
|
||||
@ -617,15 +657,15 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
}
|
||||
|
||||
return AuAtomicCompareExchange(&this->state_, iCurState + 1, iCurState) == iCurState;
|
||||
return AuAtomicCompareExchange(&this->iState_, iCurState + 1, iCurState) == iCurState;
|
||||
}
|
||||
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockWrite()
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::TryLockWriteScatterSwitch()
|
||||
{
|
||||
for (AU_ITERATE_N(i, kRWThreadWriterHardContextSwitchBias))
|
||||
{
|
||||
auto curVal = this->state_;
|
||||
auto curVal = this->iState_;
|
||||
|
||||
if (curVal < 0)
|
||||
{
|
||||
@ -638,7 +678,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
if (this->reentrantWriteLockHandle_ == GetThreadCookie())
|
||||
{
|
||||
AuAtomicSub(&this->state_, 1);
|
||||
AuAtomicSub(&this->iState_, 1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -654,7 +694,7 @@ namespace Aurora::Threading::Primitives
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AuAtomicCompareExchange(&this->state_, -1, curVal) == curVal)
|
||||
if (AuAtomicCompareExchange(&this->iState_, -1, curVal) == curVal)
|
||||
{
|
||||
this->reentrantWriteLockHandle_ = GetThreadCookie();
|
||||
return true;
|
||||
@ -669,13 +709,13 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
AuInt32 uVal {};
|
||||
|
||||
if (this->state_ < 0)
|
||||
if (this->iState_ < 0)
|
||||
{
|
||||
SysAssertDbg(this->reentrantWriteLockHandle_ == GetThreadCookie());
|
||||
return;
|
||||
}
|
||||
|
||||
uVal = AuAtomicSub(&this->state_, 1);
|
||||
uVal = AuAtomicSub(&this->iState_, 1);
|
||||
|
||||
bool bAlt {};
|
||||
if constexpr (bIsWriteRecursionAllowed)
|
||||
@ -690,22 +730,21 @@ namespace Aurora::Threading::Primitives
|
||||
if (!gUseFutexRWLock)
|
||||
{
|
||||
#if 0
|
||||
AU_LOCK_GUARD(this->mutex_); /* actually locking this->state_, out of branch. required for the mutually exclusive correctness of the condition. this is a fence. */
|
||||
bElevation = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
RWLockAcquire; /* actually locking this->iState_, out of branch. required for the mutually exclusive correctness of the condition. this is a fence. */
|
||||
bElevation = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
#else
|
||||
bElevation = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
bElevation = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
|
||||
// Do barrier to ensure the sleep count is incremented and therefore validate the condition is in a to-wake state
|
||||
if (bElevation)
|
||||
{
|
||||
this->mutex_.Lock();
|
||||
this->mutex_.Unlock();
|
||||
RWLockBarrierSelf();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
bElevation = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
bElevation = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
}
|
||||
|
||||
if (bElevation)
|
||||
@ -726,19 +765,18 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (!gUseFutexRWLock)
|
||||
{
|
||||
AuAtomicStore(&this->state_, 0);
|
||||
AuAtomicStore(&this->iState_, 0);
|
||||
|
||||
bElevationPending = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
bElevationPending = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
if (bElevationPending)
|
||||
{
|
||||
this->mutex_.Lock();
|
||||
this->mutex_.Unlock();
|
||||
RWLockBarrierSelf();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AuAtomicStore(&this->state_, 0);
|
||||
bElevationPending = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
AuAtomicStore(&this->iState_, 0);
|
||||
bElevationPending = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
}
|
||||
|
||||
if (bElevationPending)
|
||||
@ -759,7 +797,7 @@ namespace Aurora::Threading::Primitives
|
||||
AuInt32 curVal {};
|
||||
do
|
||||
{
|
||||
curVal = this->state_;
|
||||
curVal = this->iState_;
|
||||
if (curVal != -1)
|
||||
{
|
||||
continue;
|
||||
@ -767,24 +805,23 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
this->reentrantWriteLockHandle_ = 0;
|
||||
}
|
||||
while (AuAtomicCompareExchange(&this->state_, val = (curVal + 1), curVal) != curVal);
|
||||
while (AuAtomicCompareExchange(&this->iState_, val = (curVal + 1), curVal) != curVal);
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
{
|
||||
if (!gUseFutexRWLock)
|
||||
{
|
||||
bElevationPending = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
bElevationPending = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
|
||||
if (bElevationPending)
|
||||
{
|
||||
this->mutex_.Lock();
|
||||
this->mutex_.Unlock();
|
||||
RWLockBarrierSelf();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bElevationPending = AuAtomicLoad(&this->writersPending_) > 0;
|
||||
bElevationPending = AuAtomicLoad(&this->dwWritersPending_) > 0;
|
||||
}
|
||||
|
||||
if (bElevationPending)
|
||||
@ -802,7 +839,7 @@ namespace Aurora::Threading::Primitives
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::UpgradeReadToWrite(AuUInt64 uTimeout)
|
||||
{
|
||||
if (this->state_ == 1)
|
||||
if (this->iState_ == 1)
|
||||
{
|
||||
if (gUseFutexRWLock)
|
||||
{
|
||||
@ -813,7 +850,7 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
else
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
RWLockAcquire;
|
||||
|
||||
if (this->UpgradeReadToWriteDoUpgrade())
|
||||
{
|
||||
@ -826,10 +863,10 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (!gUseFutexRWLock)
|
||||
{
|
||||
AuAtomicAdd(&this->writersPending_, 1);
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
AuAtomicAdd(&this->dwWritersPending_, 1);
|
||||
RWLockAcquire;
|
||||
|
||||
while (this->state_ != 1)
|
||||
while (this->iState_ != 1)
|
||||
{
|
||||
AuInt64 iSecondTimeout {};
|
||||
|
||||
@ -839,7 +876,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (iSecondTimeout <= 0)
|
||||
{
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
AuAtomicSub(&this->dwWritersPending_, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -850,12 +887,12 @@ namespace Aurora::Threading::Primitives
|
||||
if (!this->GetConditionWriter().WaitForSignalNsEx(&this->mutex_, iSecondTimeout))
|
||||
#endif
|
||||
{
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
AuAtomicSub(&this->dwWritersPending_, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
AuAtomicSub(&this->dwWritersPending_, 1);
|
||||
return this->UpgradeReadToWriteDoUpgrade();
|
||||
}
|
||||
else
|
||||
@ -865,14 +902,14 @@ namespace Aurora::Threading::Primitives
|
||||
auto pSemaphore = this->GetFutexConditionWriter();
|
||||
|
||||
AuInt32 iCurState;
|
||||
while ((iCurState = AuAtomicLoad(&this->state_)) != 1)
|
||||
while ((iCurState = AuAtomicLoad(&this->iState_)) != 1)
|
||||
{
|
||||
bool bStatusTwo {};
|
||||
bool bStatus {};
|
||||
|
||||
AuAtomicAdd(&this->writersPending_, 1);
|
||||
AuAtomicAdd(&this->dwWritersPending_, 1);
|
||||
static const AuUInt32 kExpect { 0 };
|
||||
if ((iCurState = AuAtomicLoad(&this->state_)) == 1)
|
||||
if ((iCurState = AuAtomicLoad(&this->iState_)) == 1)
|
||||
{
|
||||
bStatus = true;
|
||||
bStatusTwo = true;
|
||||
@ -881,7 +918,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
bStatus = InternalLTSWaitOnAddressHighRes(pSemaphore, &kExpect, sizeof(kExpect), uEndTime);
|
||||
}
|
||||
AuAtomicSub(&this->writersPending_, 1);
|
||||
AuAtomicSub(&this->dwWritersPending_, 1);
|
||||
|
||||
if (!bStatus)
|
||||
{
|
||||
@ -921,7 +958,7 @@ namespace Aurora::Threading::Primitives
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::UpgradeReadToWriteDoUpgrade()
|
||||
{
|
||||
if (AuAtomicCompareExchange(&this->state_, -1, 1) == 1)
|
||||
if (AuAtomicCompareExchange(&this->iState_, -1, 1) == 1)
|
||||
{
|
||||
this->reentrantWriteLockHandle_ = GetThreadCookie();
|
||||
return true;
|
||||
@ -935,29 +972,19 @@ namespace Aurora::Threading::Primitives
|
||||
template<bool bIsWriteRecursionAllowed>
|
||||
bool RWLockImpl<bIsWriteRecursionAllowed>::DowngradeWriteToRead()
|
||||
{
|
||||
if (gUseFutexRWLock)
|
||||
if (AuAtomicCompareExchange(&this->iState_, 1, -1) == -1)
|
||||
{
|
||||
if (AuAtomicCompareExchange(&this->state_, 1, -1) == -1)
|
||||
if (!gUseFutexRWLock)
|
||||
{
|
||||
this->SignalManyReader();
|
||||
return true;
|
||||
RWLockBarrierSelf();
|
||||
}
|
||||
|
||||
return false;
|
||||
this->SignalManyReader();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AU_LOCK_GUARD(this->mutex_);
|
||||
|
||||
if (AuAtomicCompareExchange(&this->state_, 1, -1) == -1)
|
||||
{
|
||||
this->SignalManyReader();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,14 +69,18 @@ namespace Aurora::Threading::Primitives
|
||||
auline bool LockWriteNS(AuUInt64 timeout);// override;
|
||||
auline bool LockWriteNSAbs(AuUInt64 timeout);// override;
|
||||
auline bool TryLockRead();// override;
|
||||
template<bool CheckWrite>
|
||||
template<bool bCheckWrite>
|
||||
auline bool TryLockReadNoSpin();
|
||||
auline bool TryLockWrite();// override;
|
||||
auline bool TryLockWriteScatterSwitch();// override;
|
||||
auline void UnlockRead();// override;
|
||||
auline void UnlockWrite();// override;
|
||||
|
||||
|
||||
auline bool LockWriteNSAbsSecondPath();// override;
|
||||
auline void WriterWake();
|
||||
auline bool WriterSleep(AuUInt64 qwTimeoutNS);
|
||||
auline bool WriterTryLock();
|
||||
auline void FutexWriterWake();
|
||||
auline bool TryLockWriteMaybeSpin();// override;
|
||||
auline bool TryLockWriteNoSpin();// override;
|
||||
auline bool LockWriteNSAbsUnlocked(AuUInt64 qwTimeoutNS);// override;
|
||||
|
||||
bool UpgradeReadToWrite(AuUInt64 timeout) override;
|
||||
@ -98,8 +102,8 @@ namespace Aurora::Threading::Primitives
|
||||
auline void SignalManyWriter(int iBias = 0);
|
||||
|
||||
auline AuUInt32 *GetReadSleepCounter();
|
||||
private:
|
||||
|
||||
private:
|
||||
RWLockAccessView<true, RWLockImpl> read_;
|
||||
RWLockAccessView<false, RWLockImpl> write_;
|
||||
|
||||
@ -112,8 +116,9 @@ namespace Aurora::Threading::Primitives
|
||||
char conditionVariableWriter_[kSizeOfDummyCondVar] {};
|
||||
#endif
|
||||
ThreadCookie_t reentrantWriteLockHandle_ {};
|
||||
volatile AuInt32 state_ {};
|
||||
AuInt32 writersPending_ {};
|
||||
|
||||
AuAInt32 iState_ {};
|
||||
AuAInt32 dwWritersPending_ {};
|
||||
|
||||
public:
|
||||
cstatic const AuUInt8 kOffsetOfRead = AuOffsetOf(&RWLockImpl::read_);
|
||||
|
Loading…
Reference in New Issue
Block a user