diff --git a/Include/Aurora/Threading/SpinTime.hpp b/Include/Aurora/Threading/SpinTime.hpp index 51a515f7..763b288f 100644 --- a/Include/Aurora/Threading/SpinTime.hpp +++ b/Include/Aurora/Threading/SpinTime.hpp @@ -14,4 +14,5 @@ namespace Aurora::Threading AUKN_SYM void SetSpinCountTimeout(AuUInt8 uTimeout); AUKN_SYM AuUInt8 GetSpinCountTimeout(); AUKN_SYM void SetThreadLocalAdditionalSpinCountTimeout(AuUInt8 uTimeout); + AUKN_SYM AuUInt32 GetTotalSpinCountTimeout(); } \ No newline at end of file diff --git a/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp b/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp index 61369837..c3294fbb 100644 --- a/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp +++ b/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp @@ -171,7 +171,7 @@ namespace Aurora::Threading::Waitables auline bool TryLock2() { - for (AU_ITERATE_N(i, AuUInt(1u) << AuUInt(Threading::GetSpinCountTimeout()))) + for (AU_ITERATE_N(i, AuUInt(GetTotalSpinCountTimeout()))) { #if defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_X64) _mm_pause(); diff --git a/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp b/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp index 069b2735..a3917595 100644 --- a/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp +++ b/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp @@ -30,7 +30,7 @@ namespace Aurora::Threading::Waitables } #if defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_X64) - for (AU_ITERATE_N(i, AuUInt(1u) << AuUInt(Threading::GetSpinCountTimeout()))) + for (AU_ITERATE_N(i, AuUInt(GetTotalSpinCountTimeout()))) { _mm_pause(); diff --git a/Include/Aurora/Threading/Waitables/FutexWaitable.hpp b/Include/Aurora/Threading/Waitables/FutexWaitable.hpp index e7412bd8..a1ac0ec3 100644 --- a/Include/Aurora/Threading/Waitables/FutexWaitable.hpp +++ b/Include/Aurora/Threading/Waitables/FutexWaitable.hpp @@ -19,28 +19,33 @@ namespace Aurora::Threading::Waitables AU_NO_COPY_NO_MOVE(FutexWaitable); + inline bool TryLockNoSpin() + { + return AuAtomicTestAndSet(&this->uAtomicState, 0u) == 0; + } + inline bool TryLock() override { - if (AuAtomicTestAndSet(&this->uAtomicState, 0u)) + if (TryLockNoSpin()) { return true; } #if defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_X64) - for (AU_ITERATE_N(i, AuUInt(1u) << AuUInt(Threading::GetSpinCountTimeout()))) + for (AU_ITERATE_N(i, AuUInt(GetTotalSpinCountTimeout()))) { _mm_pause(); - if (AuAtomicTestAndSet(&this->uAtomicState, 0u)) + if (TryLockNoSpin()) { return true; } } #else static const AuUInt32 kRef { 1 }; - if (TryWaitOnAddress(&this->uAtomicState, &kRef, sizeof(kRef))) + if (TryWaitOnAddress((void *)&this->uAtomicState, &kRef, sizeof(kRef))) { - if (AuAtomicTestAndSet(&this->uAtomicState, 0u)) + if (TryLockNoSpin()) { return true; } @@ -62,11 +67,15 @@ namespace Aurora::Threading::Waitables inline void Unlock() override { + #if defined(AURORA_COMPILER_MSVC) this->uAtomicState = 0; + #else + __sync_lock_release(&this->uAtomicState); + #endif if (auto uSleeping = this->uAtomicSleeping) { - WakeOnAddress(&this->uAtomicState); + WakeOnAddress((const void *)&this->uAtomicState); } } @@ -74,10 +83,15 @@ namespace Aurora::Threading::Waitables { static const AuUInt32 kRef { 1 }; - while (!TryLock()) + if (TryLock()) + { + return; + } + + while (!TryLockNoSpin()) { AuAtomicAdd(&this->uAtomicSleeping, 1u); - WaitOnAddress(&this->uAtomicState, &kRef, sizeof(kRef), 0); + WaitOnAddress((void *)&this->uAtomicState, &kRef, sizeof(kRef), 0); AuAtomicSub(&this->uAtomicSleeping, 1u); } } @@ -95,24 +109,25 @@ namespace Aurora::Threading::Waitables inline bool LockNS(AuUInt64 qwTimeout) override { static const AuUInt32 kRef { 1 }; - if (AuAtomicTestAndSet(&this->uAtomicState, 0u)) + + if (TryLock()) { return true; } auto qwEndTime = Time::SteadyClockNS() + qwTimeout; - while (!TryLock()) + while (!TryLockNoSpin()) { bool bStatus {}; AuAtomicAdd(&this->uAtomicSleeping, 1u); - bStatus = WaitOnAddressSteady(&this->uAtomicState, &kRef, sizeof(kRef), qwEndTime); + bStatus = WaitOnAddressSteady((void *)&this->uAtomicState, &kRef, sizeof(kRef), qwEndTime); AuAtomicSub(&this->uAtomicSleeping, 1u); if (!bStatus) { - return TryLock(); + return TryLockNoSpin(); } } @@ -122,29 +137,30 @@ namespace Aurora::Threading::Waitables inline bool LockAbsNS(AuUInt64 qwTimeoutAbs) override { static const AuUInt32 kRef { 1 }; - if (AuAtomicTestAndSet(&this->uAtomicState, 0u)) + + if (TryLock()) { return true; } - while (!TryLock()) + while (!TryLockNoSpin()) { bool bStatus {}; AuAtomicAdd(&this->uAtomicSleeping, 1u); - bStatus = WaitOnAddressSteady(&this->uAtomicState, &kRef, sizeof(kRef), qwTimeoutAbs); + bStatus = WaitOnAddressSteady((void *)&this->uAtomicState, &kRef, sizeof(kRef), qwTimeoutAbs); AuAtomicSub(&this->uAtomicSleeping, 1u); if (!bStatus) { - return TryLock(); + return TryLockNoSpin(); } } return true; } - AuUInt32 uAtomicState {}; - AuUInt32 uAtomicSleeping {}; + volatile AuUInt32 uAtomicState {}; + volatile AuUInt32 uAtomicSleeping {}; }; } \ No newline at end of file diff --git a/Source/Threading/Primitives/SMTYield.cpp b/Source/Threading/Primitives/SMTYield.cpp index d5e29f25..b2c29c18 100644 --- a/Source/Threading/Primitives/SMTYield.cpp +++ b/Source/Threading/Primitives/SMTYield.cpp @@ -25,6 +25,18 @@ namespace Aurora::Threading gHasThreadLocalTimeout = 1; tlSpinCountLocal = uTimeout; } + + AUKN_SYM AuUInt32 GetTotalSpinCountTimeout() + { + AuUInt32 uCount {}; + uCount = 1u << AuUInt32(gRuntimeConfig.threadingConfig.uSpinLoopPowerA); + if (gHasThreadLocalTimeout) + { + uCount += 1u << AuUInt32(tlSpinCountLocal); + } + return uCount; + } + } namespace Aurora::Threading::Primitives