From a977f0d1b50da078d612c0302deda4ea154e8d4f Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Mon, 10 Jul 2023 13:12:17 +0100 Subject: [PATCH] [*] NT: backport unix optimization - no spin during spurious wake up --- .../Primitives/AuConditionMutex.NT.cpp | 19 +++++++++++++++-- .../Primitives/AuConditionMutex.NT.hpp | 3 +++ Source/Threading/Primitives/AuMutex.NT.cpp | 21 ++++++++++++------- Source/Threading/Primitives/AuMutex.NT.hpp | 2 ++ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Source/Threading/Primitives/AuConditionMutex.NT.cpp b/Source/Threading/Primitives/AuConditionMutex.NT.cpp index 2311637e..dcaf89ab 100644 --- a/Source/Threading/Primitives/AuConditionMutex.NT.cpp +++ b/Source/Threading/Primitives/AuConditionMutex.NT.cpp @@ -48,17 +48,32 @@ namespace Aurora::Threading::Primitives #else return DoTryIf([=]() { - return !AuAtomicTestAndSet(&this->lock_.uWaitCount, 0); + return this->TryLockNoSpin(); }); #endif } + bool Win32ConditionMutex::TryLockNoSpin() + { + #if defined(AURORA_FORCE_SRW_LOCKS) + return ::TryAcquireSRWLockExclusive(&this->lock_); + #else + return AuAtomicTestAndSet(&this->lock_.uWaitCount, 0) == 0; + #endif + } + void Win32ConditionMutex::Lock() { #if defined(AURORA_FORCE_SRW_LOCKS) ::AcquireSRWLockExclusive(&this->lock_); #else - while (!TryLock()) + + if (this->TryLock()) + { + return; + } + + while (!this->TryLockNoSpin()) { auto &uValueRef = this->lock_.uWaitCount; auto uValue = uValueRef | 1; diff --git a/Source/Threading/Primitives/AuConditionMutex.NT.hpp b/Source/Threading/Primitives/AuConditionMutex.NT.hpp index da37790b..07771192 100644 --- a/Source/Threading/Primitives/AuConditionMutex.NT.hpp +++ b/Source/Threading/Primitives/AuConditionMutex.NT.hpp @@ -24,6 +24,7 @@ namespace Aurora::Threading::Primitives inline HANDLE gKeyedEventHandle { INVALID_HANDLE_VALUE }; + // Actually NT5.x struct NT4Mutex { volatile AuUInt32 uWaitCount {}; // yields while bits are high, dec to release one from the semaphore yield @@ -39,6 +40,8 @@ namespace Aurora::Threading::Primitives auline void Unlock() override; AuUInt GetOSHandle() override; + auline bool TryLockNoSpin(); + #if !defined(AURORA_FORCE_SRW_LOCKS) NT4Mutex lock_; #else diff --git a/Source/Threading/Primitives/AuMutex.NT.cpp b/Source/Threading/Primitives/AuMutex.NT.cpp index 4bc29d90..e240bbcc 100644 --- a/Source/Threading/Primitives/AuMutex.NT.cpp +++ b/Source/Threading/Primitives/AuMutex.NT.cpp @@ -48,10 +48,15 @@ namespace Aurora::Threading::Primitives { return DoTryIf([=]() { - return AuAtomicTestAndSet(&this->state_, 0) == 0; + return this->TryLockNoSpin(); }); } + bool MutexImpl::TryLockNoSpin() + { + return AuAtomicTestAndSet(&this->state_, 0) == 0; + } + bool MutexImpl::HasLockImplementation() { return true; @@ -77,7 +82,7 @@ namespace Aurora::Threading::Primitives { bool returnValue = false; - if (TryLock()) + if (this->TryLock()) { return true; } @@ -87,7 +92,7 @@ namespace Aurora::Threading::Primitives if (gUseNativeWaitMutex) { - while (!TryLock()) + while (!this->TryLockNoSpin()) { auto &uValueRef = this->state_; auto uValue = uValueRef | 1; @@ -110,13 +115,13 @@ namespace Aurora::Threading::Primitives ::AcquireSRWLockShared(&this->atomicHolder_); BOOL status = false; - while (!this->TryLock()) + while (!this->TryLockNoSpin()) { AuUInt32 uTimeoutMS = INFINITE; if (uTimeout != 0) { - uStartTime = Time::SteadyClockNS(); + auto uStartTime = Time::SteadyClockNS(); if (uStartTime >= uEndTime) { goto exitWin32; @@ -146,7 +151,7 @@ namespace Aurora::Threading::Primitives if (!uTimeout) { - while (!TryLock()) + while (!this->TryLockNoSpin()) { auto &uValueRef = this->state_; auto uValue = uValueRef | 1; @@ -169,14 +174,14 @@ namespace Aurora::Threading::Primitives auto uEndTimeWall = AuTime::CurrentClockNS() + uTimeout; bool bFailed {}; - while (bFailed || (!TryLock())) + while (bFailed || (!this->TryLockNoSpin())) { auto uValue = uValueRef | 1; if (!bFailed && AuTime::SteadyClockNS() >= uEndTimeSteady) { - returnValue = TryLock(); + returnValue = this->TryLock(); break; } diff --git a/Source/Threading/Primitives/AuMutex.NT.hpp b/Source/Threading/Primitives/AuMutex.NT.hpp index 1a338ea8..dd8944e9 100644 --- a/Source/Threading/Primitives/AuMutex.NT.hpp +++ b/Source/Threading/Primitives/AuMutex.NT.hpp @@ -22,6 +22,8 @@ namespace Aurora::Threading::Primitives bool LockNS(AuUInt64 timeout) override; void Unlock() override; + auline bool TryLockNoSpin(); + private: #if defined(AURORA_FORCE_SRW_LOCKS) SRWLOCK atomicHolder_;