[*] 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:
parent
02684d543e
commit
e5981a5747
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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_;
|
||||
};
|
||||
}
|
||||
|
@ -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_);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user