[*] Reintroduce the older implementation based on Vista sync primitives when best implementation under NT 5.1 apis isn't available (microsoft being cunts under the false guise of sandboxing xbox and uwp)

This commit is contained in:
Reece Wilson 2023-03-16 18:25:23 +00:00
parent 02684d543e
commit e5981a5747
8 changed files with 112 additions and 21 deletions

View File

@ -334,9 +334,14 @@ namespace Aurora
struct ThreadingConfig
{
bool bNoThreadNames { false };
bool bPlatformIsSMPProcessorOptimized { true }; // whether to attempt to using mm_pause or similar before yielding
AuUInt8 uSpinLoopPowerA { 7 }; // nudgable spinloop power
};
bool bPlatformIsSMPProcessorOptimized { true }; // Whether to attempt to using mm_pause or similar before yielding into the kernel
AuUInt8 uSpinLoopPowerA { 7 }; // Nudgable spinloop power. This is our local userland niceness factor; where 1 << n is the amount of yield instructions to stall for
bool bPreferNt51XpMutexesOver81 { true }; // Fun Fact: Undocumented Windows XP APIs are still better than whatever the fuck shit fest they sharted out under Windows Vista and 8.1
}; // Wth the former set of apis, we are still nothing more than a futex intended for nothing more than x86 bittestandset with undefined
// bahviour on the higher bits, and we're crippled by some annoying thread switch function. Windows Vista superseded the dumb kernel-io
// based switching apis everyone thought they had to use with bloat on top of this very same 5.1 era api.
// And to end it all off, Windows 8.1 wait/wake on address forces relative millisecond precision, in the first (?) MS OS to drop tick based [re]scheduling.
// Our main mutex is one edge case where undcoumented XP era scheduling apis are better than the garbage indiasoft wants you to use in <current year>.
struct RuntimeStartInfo
{
@ -346,8 +351,8 @@ namespace Aurora
AsyncConfig async;
FIOConfig fio;
DebugConfig debug;
bool bFIODisableBatching {true};
bool bIOLinuxHasProcIpcPerms {false};
bool bFIODisableBatching { true };
bool bIOLinuxHasProcIpcPerms { false };
ThreadingConfig threadingConfig;
};

View File

@ -17,6 +17,7 @@ namespace Aurora::Threading::Primitives
Win32ConditionMutex::Win32ConditionMutex()
{
#if !defined(AURORA_FORCE_SRW_LOCKS)
if (gKeyedEventHandle == INVALID_HANDLE_VALUE)
{
if (!pNtCreateKeyedEvent)
@ -26,6 +27,9 @@ namespace Aurora::Threading::Primitives
pNtCreateKeyedEvent(&gKeyedEventHandle, -1, NULL, 0);
}
#else
::InitializeSRWLock(&this->lock_);
#endif
}
Win32ConditionMutex::~Win32ConditionMutex()
@ -34,14 +38,21 @@ namespace Aurora::Threading::Primitives
bool Win32ConditionMutex::TryLock()
{
#if defined(AURORA_FORCE_SRW_LOCKS)
return ::TryAcquireSRWLockExclusive(&this->lock_);
#else
return DoTryIf([=]()
{
return !AuAtomicTestAndSet(&this->lock_.uWaitCount, 0);
});
#endif
}
void Win32ConditionMutex::Lock()
{
#if defined(AURORA_FORCE_SRW_LOCKS)
::AcquireSRWLockExclusive(&this->lock_);
#else
while (!TryLock())
{
auto &uValueRef = this->lock_.uWaitCount;
@ -54,10 +65,14 @@ namespace Aurora::Threading::Primitives
AuAtomicSub(&uValueRef, FAST_M_WAKE);
}
}
#endif
}
void Win32ConditionMutex::Unlock()
{
#if defined(AURORA_FORCE_SRW_LOCKS)
::ReleaseSRWLockExclusive(&this->lock_);
#else
auto &uValueRef = this->lock_.uWaitCount;
while (true)
@ -99,6 +114,7 @@ namespace Aurora::Threading::Primitives
SMPPause();
}
#endif
}
AuUInt Win32ConditionMutex::GetOSHandle()

View File

@ -32,7 +32,11 @@ namespace Aurora::Threading::Primitives
auline void Unlock() override;
AuUInt GetOSHandle() override;
#if !defined(AURORA_FORCE_SRW_LOCKS)
NT4Mutex lock_;
#else
SRWLOCK lock_;
#endif
};
using ConditionMutexImpl = Win32ConditionMutex;

View File

@ -21,20 +21,36 @@ namespace Aurora::Threading::Primitives
ConditionVariableImpl::ConditionVariableImpl(const AuSPtr<IConditionMutex> &pMutex) :
mutex_(AuStaticCast<Win32ConditionMutex>(pMutex))
{
#if defined(AURORA_FORCE_SRW_LOCKS)
::InitializeConditionVariable(&this->winCond_);
#endif
}
AuSPtr<IConditionMutex> ConditionVariableImpl::GetMutex()
{
return mutex_;
return this->mutex_;
}
bool ConditionVariableImpl::WaitForSignal(AuUInt32 uTimeout)
{
#if !defined(AURORA_FORCE_SRW_LOCKS)
return WaitForSignalNS(AuMSToNS<AuUInt64>(uTimeout));
#else
auto bOK = ::SleepConditionVariableSRW(&this->winCond_, reinterpret_cast<PSRWLOCK>(this->mutex_->GetOSHandle()), uTimeout ? uTimeout : INFINITE, 0);
if (!bOK)
{
SysAssert(GetLastError() == ERROR_TIMEOUT, "SleepConditionVariable failure");
return false;
}
return true;
#endif
}
bool ConditionVariableImpl::WaitForSignalNS(AuUInt64 qwTimeout)
{
#if !defined(AURORA_FORCE_SRW_LOCKS)
bool bRet { true };
auto pThatMutex = reinterpret_cast<NT4Mutex *>(&this->mutex_->lock_);
@ -42,7 +58,9 @@ namespace Aurora::Threading::Primitives
if (qwTimeout)
{
#if !defined(AU_TRUST_NT_KERNEL_SCHED_TIMEOUT)
auto uEndTimeSteady = AuTime::SteadyClockNS() + qwTimeout;
#endif
auto uEndTimeWall = AuTime::CurrentClockNS() + qwTimeout;
auto uTargetTimeNt = AuTime::ConvertTimestampNs(uEndTimeWall);
@ -51,7 +69,6 @@ namespace Aurora::Threading::Primitives
LARGE_INTEGER word;
word.QuadPart = uTargetTimeNt;
// forced smp stall
// see the "hopefully nt is smart enough" comment
bool bIOU = DoTryIf([=]()
@ -172,10 +189,50 @@ namespace Aurora::Threading::Primitives
}
}
}
#else
AuInt64 uEndTime = qwTimeout ? AuTime::SteadyClockNS() + qwTimeout : 0;
while (true)
{
AuInt64 uSecondTimeout = INFINITE;
if (qwTimeout)
{
uSecondTimeout = uEndTime - AuTime::SteadyClockNS();
if (uSecondTimeout <= 0)
{
return false;
}
uSecondTimeout = AuNSToMS<AuUInt64>(uSecondTimeout);
if (!uSecondTimeout)
{
SMPPause();
AuThreading::ContextYield();
continue;
}
}
auto bOk = ::SleepConditionVariableSRW(&this->winCond_, reinterpret_cast<PSRWLOCK>(mutex_->GetOSHandle()), uSecondTimeout, 0);
if (bOk)
{
return true;
}
else
{
SysAssert(GetLastError() == ERROR_TIMEOUT, "SleepConditionVariable failure");
}
}
#endif
}
bool ConditionVariableImpl::CheckOut(bool &bRet)
{
#if defined(AURORA_FORCE_SRW_LOCKS)
return false;
#else
return DoTryIf([&]()
{
auto uSignalNow = this->signalCount;
@ -187,10 +244,12 @@ namespace Aurora::Threading::Primitives
return AuAtomicCompareExchange(&this->signalCount, uSignalNow - 1, uSignalNow) == uSignalNow;
});
#endif
}
void ConditionVariableImpl::Signal()
{
#if !defined(AURORA_FORCE_SRW_LOCKS)
auto original = this->wlist;
auto expected = original;
expected = expected >> 2;
@ -211,10 +270,14 @@ namespace Aurora::Threading::Primitives
expected = original >> 2;
}
}
#else
::WakeConditionVariable(&this->winCond_);
#endif
}
void ConditionVariableImpl::Broadcast()
{
#if !defined(AURORA_FORCE_SRW_LOCKS)
auto original = this->wlist;
auto expected = original;
expected = expected >> 2;
@ -235,6 +298,9 @@ namespace Aurora::Threading::Primitives
original = this->wlist;
expected = original >> 2;
}
#else
::WakeAllConditionVariable(&this->winCond_);
#endif
}
AUKN_SYM IConditionVariable *ConditionVariableNew(const AuSPtr<IConditionMutex> &pMutex)

View File

@ -25,8 +25,12 @@ namespace Aurora::Threading::Primitives
bool CheckOut(bool &bRet);
private:
#if defined(AURORA_FORCE_SRW_LOCKS)
CONDITION_VARIABLE winCond_;
#else
AuUInt32 wlist {};
AuUInt32 signalCount {};
#endif
AuSPtr<Win32ConditionMutex> mutex_;
};
}

View File

@ -24,7 +24,7 @@ namespace Aurora::Threading::Primitives
{
if (!pWaitOnAddress)
{
#if 0
#if defined(AURORA_FORCE_SRW_LOCKS)
::InitializeSRWLock(&this->atomicHolder_);
::InitializeConditionVariable(&this->wakeup_);
#endif
@ -46,7 +46,7 @@ namespace Aurora::Threading::Primitives
{
return DoTryIf([=]()
{
return ::_interlockedbittestandset((volatile LONG *)&this->state_, 0) == 0;
return AuAtomicTestAndSet(&this->state_, 0) == 0;
});
}
@ -78,7 +78,8 @@ namespace Aurora::Threading::Primitives
AuUInt64 uStartTime = Time::SteadyClockNS();
AuUInt64 uEndTime = uStartTime + uTimeout;
if (pWaitOnAddress)
if (pWaitOnAddress &&
!gRuntimeConfig.threadingConfig.bPreferNt51XpMutexesOver81)
{
auto state = this->state_;
while (::_interlockedbittestandset((volatile LONG *)&this->state_, 0) != 0)
@ -113,7 +114,7 @@ namespace Aurora::Threading::Primitives
}
else
{
#if 0
#if defined(AURORA_FORCE_SRW_LOCKS)
::AcquireSRWLockShared(&this->atomicHolder_);
BOOL status = false;
@ -226,9 +227,10 @@ namespace Aurora::Threading::Primitives
void Mutex::Unlock()
{
if (!pWaitOnAddress)
if (!pWaitOnAddress ||
gRuntimeConfig.threadingConfig.bPreferNt51XpMutexesOver81)
{
#if 0
#if defined(AURORA_FORCE_SRW_LOCKS)
::AcquireSRWLockExclusive(&this->atomicHolder_);
this->state_ = 0;
::ReleaseSRWLockExclusive(&this->atomicHolder_);

View File

@ -23,7 +23,7 @@ namespace Aurora::Threading::Primitives
void Unlock() override;
private:
#if 0
#if defined(AURORA_FORCE_SRW_LOCKS)
SRWLOCK atomicHolder_;
CONDITION_VARIABLE wakeup_;
#endif

View File

@ -116,15 +116,9 @@ namespace Aurora::Threading::Primitives
{
return false;
}
uSecondTimeout = AuNSToMS<AuUInt64>(uSecondTimeout);
if (!uSecondTimeout)
{
return false;
}
}
if (!this->condition_.WaitForSignal(uSecondTimeout))
if (!this->condition_.WaitForSignalNS(uSecondTimeout))
{
return false;
}