[*] Win8+: Experimental primitive improvements by taking notes from Win7 cycle pinching

[*] +regression in condvar
This commit is contained in:
Reece Wilson 2023-07-09 23:33:12 +01:00
parent 355f7db711
commit 8c84ecf892
4 changed files with 71 additions and 26 deletions

View File

@ -67,17 +67,16 @@ namespace Aurora::Threading::Primitives
{ {
if (gUseNativeWaitCondvar) if (gUseNativeWaitCondvar)
{ {
auto uCurrentValue = uValue + kFutexBitWait; // TODO: 1 bit? auto uCurrentValue = uValue + kFutexBitWait;
InternalLTSWaitOnAddressHighRes((void *)&uValueRef, &uCurrentValue, sizeof(uCurrentValue), 0); InternalLTSWaitOnAddressHighRes((void *)&uValueRef, &uCurrentValue, sizeof(uCurrentValue), 0);
} }
else else
{ {
pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL);
}
AuAtomicSub(&uValueRef, kFutexBitWake); AuAtomicSub(&uValueRef, kFutexBitWake);
} }
} }
}
#endif #endif
} }
@ -86,11 +85,38 @@ namespace Aurora::Threading::Primitives
#if defined(AURORA_FORCE_SRW_LOCKS) #if defined(AURORA_FORCE_SRW_LOCKS)
::ReleaseSRWLockExclusive(&this->lock_); ::ReleaseSRWLockExclusive(&this->lock_);
#else #else
auto &uValueRef = this->lock_.uWaitCount;
// Mirrors: ./AuMutex.NT.cpp // Mirrors: ./AuMutex.NT.cpp
// keep this codeblock in parity // keep this codeblock in parity
// defer to the comments in that source file // defer to the comments in that source file
if (gUseNativeWaitCondvar)
{
auto &uValueRef = this->lock_.uWaitCount;
*(AuUInt8 *)&uValueRef = 0;
while (true)
{
auto uValue = uValueRef;
if (uValue < kFutexBitWait)
{
return;
}
if (AuAtomicCompareExchange(&uValueRef, uValue - kFutexBitWait, uValue) == uValue)
{
pWakeByAddressSingle((void *)&this->lock_.uWaitCount);
return;
}
SMPPause();
}
return;
}
auto &uValueRef = this->lock_.uWaitCount;
#if defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_X64) #if defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_X64)
*(AuUInt8 *)&uValueRef = 0; *(AuUInt8 *)&uValueRef = 0;
#else #else
@ -126,15 +152,8 @@ namespace Aurora::Threading::Primitives
} }
if (AuAtomicCompareExchange(&uValueRef, uValue - kFutexBitWait + kFutexBitWake, uValue) == uValue) if (AuAtomicCompareExchange(&uValueRef, uValue - kFutexBitWait + kFutexBitWake, uValue) == uValue)
{
if (gUseNativeWaitCondvar)
{
pWakeByAddressSingle((void *)&uValueRef);
}
else
{ {
pNtReleaseKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); pNtReleaseKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL);
}
return; return;
} }

View File

@ -18,8 +18,8 @@ namespace Aurora::Threading::Primitives
// sub = and // sub = and
// assuming the bits are unset/set respectively // assuming the bits are unset/set respectively
static auto const kFutexBitWake = 256u; // 1^8 static auto const kFutexBitWake = 256u; // 2^8
static auto const kFutexBitWait = 512u; // 1^9, next byte over static auto const kFutexBitWait = 512u; // 2^9, next byte over
inline HANDLE gKeyedEventHandle { INVALID_HANDLE_VALUE }; inline HANDLE gKeyedEventHandle { INVALID_HANDLE_VALUE };

View File

@ -151,6 +151,8 @@ namespace Aurora::Threading::Primitives
} }
else else
{ {
pMutex->Unlock();
// Obligatory Windows XP+ resched // Obligatory Windows XP+ resched
bRet = pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, nullptr) != NTSTATUS_TIMEOUT; bRet = pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, nullptr) != NTSTATUS_TIMEOUT;
} }

View File

@ -82,21 +82,24 @@ namespace Aurora::Threading::Primitives
return true; return true;
} }
AuUInt64 uStartTime = Time::SteadyClockNS(); AuUInt64 uEndTime = uTimeout ? Time::SteadyClockNS() + uTimeout : 0;
AuUInt64 uEndTime = uTimeout ? uStartTime + uTimeout : 0;
int iYieldCounter {}; int iYieldCounter {};
if (gUseNativeWaitMutex) if (gUseNativeWaitMutex)
{ {
auto state = this->state_; while (!TryLock())
while (::_interlockedbittestandset((volatile LONG *)&this->state_, 0) != 0)
{ {
if (!InternalLTSWaitOnAddressHighRes((void *)&this->state_, &state, sizeof(this->state_), uEndTime)) auto &uValueRef = this->state_;
auto uValue = uValueRef | 1;
auto uNextValue = uValue + kFutexBitWait;
if (AuAtomicCompareExchange(&uValueRef, uNextValue, uValue) == uValue)
{
if (!InternalLTSWaitOnAddressHighRes((void *)&uValueRef, &uNextValue, sizeof(uNextValue), uEndTime))
{ {
return false; return false;
} }
}
state = this->state_;
} }
return true; return true;
@ -218,8 +221,29 @@ namespace Aurora::Threading::Primitives
{ {
if (gUseNativeWaitMutex) if (gUseNativeWaitMutex)
{ {
this->state_ = 0; auto &uValueRef = this->state_;
*(AuUInt8 *)&uValueRef = 0;
while (true)
{
auto uValue = uValueRef;
if (uValue < kFutexBitWait)
{
return;
}
if (AuAtomicCompareExchange(&uValueRef, uValue - kFutexBitWait, uValue) == uValue)
{
pWakeByAddressSingle((void *)&this->state_); pWakeByAddressSingle((void *)&this->state_);
return;
}
SMPPause();
}
return;
} }
else else
{ {