[*] Thread primitives optimization
[*] Fix wake on address regression
This commit is contained in:
parent
1a71a7dd41
commit
0747ff230e
@ -108,7 +108,13 @@ namespace Aurora::Threading
|
||||
|
||||
if (!this->bAlive)
|
||||
{
|
||||
#if !defined(WOA_SEMAPHORE_MODE)
|
||||
this->mutex.Unlock();
|
||||
#endif
|
||||
(void)gProcessWaitables.WaitBufferFrom(this->pAddress, this->uSize);
|
||||
#if !defined(WOA_SEMAPHORE_MODE)
|
||||
this->mutex.Lock();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -116,7 +122,7 @@ namespace Aurora::Threading
|
||||
this->semaphore->LockAbsNS(uEndTime);
|
||||
#else
|
||||
auto uTimeRemNS = uEndTime - uNow;
|
||||
this->variable.WaitForSignalNsEx(&this->mutex, uTimeRemNS);
|
||||
this->variable.WaitForSignalNsEx(&this->mutex, uTimeRemNS, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -131,14 +137,20 @@ namespace Aurora::Threading
|
||||
{
|
||||
if (!this->bAlive)
|
||||
{
|
||||
#if !defined(WOA_SEMAPHORE_MODE)
|
||||
this->mutex.Unlock();
|
||||
#endif
|
||||
(void)gProcessWaitables.WaitBufferFrom(this->pAddress, this->uSize);
|
||||
#if !defined(WOA_SEMAPHORE_MODE)
|
||||
this->mutex.Lock();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(WOA_SEMAPHORE_MODE)
|
||||
this->semaphore->Lock();
|
||||
#else
|
||||
this->variable.WaitForSignalNsEx(&this->mutex, 0);
|
||||
this->variable.WaitForSignalNsEx(&this->mutex, 0, false);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,6 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
while (!this->TryLockNoSpin())
|
||||
{
|
||||
|
||||
int ret {};
|
||||
bool bStatus {};
|
||||
|
||||
|
@ -24,7 +24,27 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
}
|
||||
|
||||
bool ConditionVariableLinux::WaitOne(AuUInt64 qwTimeoutRelative)
|
||||
bool ConditionVariableLinux::TryTakeOneNoSpin()
|
||||
{
|
||||
auto old = this->uState_;
|
||||
return old != 0 && AuAtomicCompareExchange(&this->uState_, old - 1, old) == old;
|
||||
}
|
||||
|
||||
bool ConditionVariableLinux::TryTakeOneSpin()
|
||||
{
|
||||
if (ThrdCfg::gPreferLinuxPrimitivesFutexNoSpin)
|
||||
{
|
||||
return this->TryTakeOneNoSpin();
|
||||
}
|
||||
|
||||
return DoTryIf([=]()
|
||||
{
|
||||
return this->TryTakeOneNoSpin();
|
||||
});
|
||||
}
|
||||
|
||||
bool ConditionVariableLinux::WaitOne(AuUInt64 qwTimeoutRelative,
|
||||
bool bSpin)
|
||||
{
|
||||
AuUInt64 uStart {};
|
||||
AuUInt64 uEnd {};
|
||||
@ -38,11 +58,7 @@ namespace Aurora::Threading::Primitives
|
||||
Time::monoabsns2ts(&tspec, uEnd);
|
||||
}
|
||||
|
||||
if (DoTryIf([=]()
|
||||
{
|
||||
auto old = this->uState_;
|
||||
return (old != 0 && AuAtomicCompareExchange(&this->uState_, old - 1, old) == old);
|
||||
}))
|
||||
if (bSpin ? this->TryTakeOneSpin() : this->TryTakeOneNoSpin())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -97,7 +113,8 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
|
||||
bool ConditionVariableLinux::WaitForSignalNsEx(LinuxConditionMutex *pMutex,
|
||||
AuUInt64 qwTimeoutRelative)
|
||||
AuUInt64 qwTimeoutRelative,
|
||||
bool bSpin)
|
||||
{
|
||||
|
||||
AuAtomicAdd(&this->uSleeping_, 1u);
|
||||
@ -107,7 +124,7 @@ namespace Aurora::Threading::Primitives
|
||||
pMutex->Unlock();
|
||||
}
|
||||
|
||||
auto bSuccess = this->WaitOne(qwTimeoutRelative);
|
||||
auto bSuccess = this->WaitOne(qwTimeoutRelative, bSpin);
|
||||
if (!bSuccess)
|
||||
{
|
||||
auto uWaiters = this->uSleeping_;
|
||||
|
@ -20,12 +20,15 @@ namespace Aurora::Threading::Primitives
|
||||
ConditionVariableLinux();
|
||||
~ConditionVariableLinux();
|
||||
|
||||
bool WaitForSignalNsEx(LinuxConditionMutex *pMutex, AuUInt64 timeout);
|
||||
bool WaitForSignalNsEx(LinuxConditionMutex *pMutex, AuUInt64 timeout, bool bSpin = true);
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
bool WaitOne(AuUInt64 qwTimeout);
|
||||
bool WaitOne(AuUInt64 qwTimeout, bool bSpin);
|
||||
|
||||
private:
|
||||
bool TryTakeOneNoSpin();
|
||||
bool TryTakeOneSpin();
|
||||
|
||||
AuUInt32 uState_ {};
|
||||
AuUInt32 uSleeping_ {};
|
||||
};
|
||||
|
@ -26,7 +26,7 @@ namespace Aurora::Threading::Primitives
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ConditionVariableNT::WaitForSignalNsEx(Win32ConditionMutex *pMutex, AuUInt64 qwTimeout)
|
||||
bool ConditionVariableNT::WaitForSignalNsEx(Win32ConditionMutex *pMutex, AuUInt64 qwTimeout, bool bSpin)
|
||||
{
|
||||
#if !defined(AURORA_FORCE_SRW_LOCKS)
|
||||
bool bRet { true };
|
||||
@ -34,9 +34,7 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (qwTimeout)
|
||||
{
|
||||
//#if defined(AU_TRUST_NT_KERNEL_SCHED_TIMEOUT)
|
||||
auto uEndTimeSteady = gUseNativeWaitCondvar ? AuTime::SteadyClockNS() + qwTimeout : 0; // we could nuke this again, if i really wanted to
|
||||
// #endif
|
||||
auto uEndTimeSteady = gUseNativeWaitCondvar ? AuTime::SteadyClockNS() + qwTimeout : 0;
|
||||
auto uEndTimeWall = AuTime::CurrentClockNS() + qwTimeout;
|
||||
auto uTargetTimeNt = AuTime::ConvertTimestampNs(uEndTimeWall);
|
||||
bool bIOU {};
|
||||
@ -65,7 +63,8 @@ namespace Aurora::Threading::Primitives
|
||||
if (gUseNativeWaitCondvar)
|
||||
{
|
||||
// Reverted: 5b495f7fd9495aa55395666e166ac499955215dc
|
||||
if (ThrdCfg::gPreferNtCondvarModernWinSpin)
|
||||
if (bSpin &&
|
||||
ThrdCfg::gPreferNtCondvarModernWinSpin)
|
||||
{
|
||||
if (this->CheckOut())
|
||||
{
|
||||
@ -73,14 +72,19 @@ namespace Aurora::Threading::Primitives
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
else if (this->CheckOutNoSpin()) {
|
||||
pMutex->Lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
AuUInt8 uBlockBit { 1 };
|
||||
bRet = InternalLTSWaitOnAddressHighRes(&this->wlist, &uBlockBit, 1, uEndTimeSteady);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reverted: 5b495f7fd9495aa55395666e166ac499955215dc
|
||||
if (ThrdCfg::gPreferNtCondvarOlderWinSpin)
|
||||
if (bSpin &&
|
||||
ThrdCfg::gPreferNtCondvarOlderWinSpin)
|
||||
{
|
||||
if (!bIOU)
|
||||
{
|
||||
@ -135,7 +139,6 @@ namespace Aurora::Threading::Primitives
|
||||
continue;
|
||||
}
|
||||
|
||||
// go for an atomic decrement while racing against ::Signal and ::Broadcast
|
||||
auto waiting = uOld - 1u;
|
||||
auto uNext = waiting << kShiftCountByBits;
|
||||
|
||||
@ -150,8 +153,8 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
else
|
||||
{
|
||||
// we good?
|
||||
if (bIOU || this->CheckOut())
|
||||
if (bIOU ||
|
||||
(bSpin ? this->CheckOut() : this->CheckOutNoSpin()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -179,7 +182,8 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
if (gUseNativeWaitCondvar)
|
||||
{
|
||||
if (ThrdCfg::gPreferNtCondvarModernWinSpin)
|
||||
if (bSpin &&
|
||||
ThrdCfg::gPreferNtCondvarModernWinSpin)
|
||||
{
|
||||
if (this->CheckOut())
|
||||
{
|
||||
@ -187,13 +191,19 @@ namespace Aurora::Threading::Primitives
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (this->CheckOutNoSpin())
|
||||
{
|
||||
pMutex->Lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
AuUInt8 uBlockBit { 1 };
|
||||
bRet = InternalLTSWaitOnAddressHighRes(&this->wlist, &uBlockBit, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ThrdCfg::gPreferNtCondvarOlderWinSpin)
|
||||
if (bSpin &&
|
||||
ThrdCfg::gPreferNtCondvarOlderWinSpin)
|
||||
{
|
||||
if (!bIOU)
|
||||
{
|
||||
@ -207,7 +217,7 @@ namespace Aurora::Threading::Primitives
|
||||
pMutex->Lock();
|
||||
|
||||
if (bIOU ||
|
||||
this->CheckOutNoSpin())
|
||||
(bSpin ? this->CheckOut() : this->CheckOutNoSpin()))
|
||||
{
|
||||
return bRet;
|
||||
}
|
||||
@ -257,33 +267,33 @@ namespace Aurora::Threading::Primitives
|
||||
#if defined(AURORA_FORCE_SRW_LOCKS)
|
||||
return false;
|
||||
#else
|
||||
auto uSignalNow = this->signalCount;
|
||||
AuUInt32 uSignalNow {};
|
||||
AuUInt32 uSignalNext {};
|
||||
|
||||
if (uSignalNow == 0)
|
||||
while (true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uSignalNow = AuAtomicLoad(&this->signalCount);
|
||||
|
||||
auto uSignalNext = uSignalNow - 1;
|
||||
|
||||
if (AuAtomicCompareExchange(&this->signalCount, uSignalNext, uSignalNow) != uSignalNow)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (kBoolRequiredLateSet)
|
||||
{
|
||||
if (uSignalNext == 0)
|
||||
if (uSignalNow == 0)
|
||||
{
|
||||
InterlockedOr((volatile LONG *)&this->wlist, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// paranoia
|
||||
#if 1
|
||||
if (AuAtomicLoad(&this->signalCount) != 0) [[unlikely]]
|
||||
{
|
||||
AuAtomicUnset(&this->wlist, 0);
|
||||
}
|
||||
#endif
|
||||
uSignalNext = uSignalNow - 1;
|
||||
|
||||
if (AuAtomicCompareExchange(&this->signalCount, uSignalNext, uSignalNow) == uSignalNow)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uSignalNext == 0)
|
||||
{
|
||||
InterlockedOr((volatile LONG *)&this->wlist, 1);
|
||||
|
||||
if (AuAtomicLoad(&this->signalCount) != 0) [[unlikely]]
|
||||
{
|
||||
AuAtomicUnset(&this->wlist, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace Aurora::Threading::Primitives
|
||||
{
|
||||
ConditionVariableNT();
|
||||
|
||||
bool WaitForSignalNsEx(Win32ConditionMutex *pMutex, AuUInt64 timeout);
|
||||
bool WaitForSignalNsEx(Win32ConditionMutex *pMutex, AuUInt64 timeout, bool bSpin = true);
|
||||
void Signal();
|
||||
void Broadcast();
|
||||
void BroadcastN(AuUInt32 nBroadcast);
|
||||
|
@ -46,7 +46,8 @@ namespace Aurora::Threading::Primitives
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::WaitForSignalNsEx(const std::shared_ptr<UnixConditionMutex> &pMutex,
|
||||
AuUInt64 qwTimeout)
|
||||
AuUInt64 qwTimeout,
|
||||
bool bSpin)
|
||||
{
|
||||
auto mutex = reinterpret_cast<pthread_mutex_t*>(pMutex->GetOSHandle());
|
||||
|
||||
|
@ -19,7 +19,9 @@ namespace Aurora::Threading::Primitives
|
||||
|
||||
AuSPtr<IConditionMutex> GetMutex() override;
|
||||
bool WaitForSignal(AuUInt32 timeout) override;
|
||||
bool WaitForSignalNsEx(const std::shared_ptr<UnixConditionMutex> &pMutex, AuUInt64 timeout);
|
||||
bool WaitForSignalNsEx(const std::shared_ptr<UnixConditionMutex> &pMutex,
|
||||
AuUInt64 qwTimeout,
|
||||
bool bSpin = true);
|
||||
bool WaitForSignalNS(AuUInt64 qwTimeout) override;
|
||||
void Signal() override;
|
||||
void Broadcast() override;
|
||||
|
@ -135,11 +135,11 @@ namespace Aurora::Threading::Primitives
|
||||
return false;
|
||||
}
|
||||
|
||||
var.WaitForSignalNsEx(&this->mutex, uEnd - uStart);
|
||||
var.WaitForSignalNsEx(&this->mutex, uEnd - uStart, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var.WaitForSignalNsEx(&this->mutex, 0);
|
||||
var.WaitForSignalNsEx(&this->mutex, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,11 +192,11 @@ namespace Aurora::Threading::Primitives
|
||||
return false;
|
||||
}
|
||||
|
||||
var.WaitForSignalNsEx(&this->mutex, qwTimeoutAbs - uStart);
|
||||
var.WaitForSignalNsEx(&this->mutex, qwTimeoutAbs - uStart, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var.WaitForSignalNsEx(&this->mutex, 0);
|
||||
var.WaitForSignalNsEx(&this->mutex, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user