From 7ce89a143f566854ce53721dac01791f63bd8442 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Sat, 19 Aug 2023 22:25:31 +0100 Subject: [PATCH] [+] FutexCondWaitable [+] (shorthand) AuMutex [+] (shorthand) AuSemaphore [+] (shorthand) AuRWRenterableLock [+] (shorthand) AuRenterableMutex [+] (shorthand) AuRWLock [+] (shorthand) AuCond [+] (shorthand) AuCondMutex [+] (shorthand) AuSpinLock [+] (shorthand) AuFutexCond --- Include/Aurora/Runtime.hpp | 11 + .../Threading/Waitables/FutexCondWaitable.hpp | 211 ++++++++++++++++++ .../Waitables/FutexSemaphoreWaitable.hpp | 12 +- .../Aurora/Threading/Waitables/Waitables.hpp | 3 +- 4 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp diff --git a/Include/Aurora/Runtime.hpp b/Include/Aurora/Runtime.hpp index cdc43522..4f1fc118 100644 --- a/Include/Aurora/Runtime.hpp +++ b/Include/Aurora/Runtime.hpp @@ -127,8 +127,19 @@ using AuMemoryViewWrite = AuMemory::MemoryViewWrite; using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead; using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite; + +using AuMutex = AuThreadPrimitives::Mutex; +using AuSemaphore = AuThreadPrimitives::Semaphore; +using AuRWRenterableLock = AuThreadPrimitives::RWRenterableLock; +using AuRenterableMutex = AuThreadPrimitives::CriticalSection; +using AuRWLock = AuThreadPrimitives::RWLock; +using AuCond = AuThreadPrimitives::ConditionVariable; +using AuCondMutex = AuThreadPrimitives::ConditionMutex; +using AuSpinLock = AuThreadPrimitives::SpinLock; + using AuFutexMutex = AuThreading::Waitables::FutexWaitable; using AuFutexSemaphore = AuThreading::Waitables::FutexSemaphoreWaitable; +using AuFutexCond = AuThreading::Waitables::FutexCondWaitable; template using AuTLSVariable = AuThreads::TLSVariable; diff --git a/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp b/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp new file mode 100644 index 00000000..943527c9 --- /dev/null +++ b/Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp @@ -0,0 +1,211 @@ +/*** + Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: FutexCondWaitable.hpp + Date: 2023-08-19 + Author: Reece +***/ +#pragma once + +#include "../WakeOnAddress.hpp" +#include "../SpinTime.hpp" + +namespace Aurora::Threading::Waitables +{ + struct FutexCondWaitable final + { + inline constexpr FutexCondWaitable() + {} + + AU_NO_COPY_NO_MOVE(FutexCondWaitable); + + template + inline bool WaitNS(T pWaitable, AuUInt64 uRelativeNanoseconds) + { + AuAtomicAdd(&this->uAtomicSleeping, 1u); + + if (pWaitable) + { + pWaitable->Unlock(); + } + + auto bSuccess = this->TryLock2() || + this->SleepOne(Time::SteadyClockNS() + uRelativeNanoseconds); + + if (!bSuccess) + { + auto uWaiters = this->uAtomicSleeping; + auto uWaitCount = 1; + + while (AuAtomicCompareExchange(&this->uAtomicSleeping, uWaiters - uWaitCount, uWaiters) != uWaiters) + { + uWaiters = this->uAtomicSleeping; + + if (uWaiters == 0) + { + break; + } + } + } + + if (pWaitable) + { + pWaitable->Lock(); + } + + return bSuccess; + } + + template + inline bool WaitAbsNS(T pWaitable, AuUInt64 uSteadyClockNanoseconds) + { + AuAtomicAdd(&this->uAtomicSleeping, 1u); + + if (pWaitable) + { + pWaitable->Unlock(); + } + + auto bSuccess = this->TryLock2() || + this->SleepOne(uSteadyClockNanoseconds); + + if (!bSuccess) + { + auto uWaiters = this->uAtomicSleeping; + auto uWaitCount = 1; + + while (AuAtomicCompareExchange(&this->uAtomicSleeping, uWaiters - uWaitCount, uWaiters) != uWaiters) + { + uWaiters = this->uAtomicSleeping; + + if (uWaiters == 0) + { + break; + } + } + } + + if (pWaitable) + { + pWaitable->Lock(); + } + + return bSuccess; + } + + auline void NotifyOne() + { + AuUInt32 uWaitCount {}; + AuUInt32 uWaiters {}; + + uWaiters = this->uAtomicSleeping; + if (uWaiters > 0) + { + AuAtomicAdd(&this->uAtomicState, 1u); + WakeOnAddress((const void *)&this->uAtomicState); + uWaitCount = 1; + } + + while (AuAtomicCompareExchange(&this->uAtomicSleeping, uWaiters - uWaitCount, uWaiters) != uWaiters) + { + uWaiters = this->uAtomicSleeping; + + if (uWaiters == 0) + { + return; + } + } + } + + auline void Broadcast() + { + AuUInt32 uWaitCount {}; + AuUInt32 uWaiters {}; + + uWaiters = this->uAtomicSleeping; + if (uWaiters > 0) + { + AuAtomicAdd(&this->uAtomicState, uWaiters); + WakeNOnAddress((const void *)&this->uAtomicState, uWaiters); + uWaitCount = 1; + } + + while (AuAtomicCompareExchange(&this->uAtomicSleeping, uWaiters - uWaitCount, uWaiters) != uWaiters) + { + uWaiters = this->uAtomicSleeping; + + if (uWaiters == 0) + { + return; + } + } + } + + auline void NotifyN(AuUInt32 uThreads) + { + AuUInt32 uWaitCount {}; + AuUInt32 uWaiters {}; + + uWaiters = this->uAtomicSleeping; + if (uWaiters > 0) + { + AuAtomicAdd(&this->uAtomicState, uThreads); + WakeNOnAddress((const void *)&this->uAtomicState, uThreads); + uWaitCount = 1; + } + + while (AuAtomicCompareExchange(&this->uAtomicSleeping, uWaiters - uWaitCount, uWaiters) != uWaiters) + { + uWaiters = this->uAtomicSleeping; + + if (uWaiters == 0) + { + return; + } + } + } + + volatile AuUInt32 uAtomicState {}; + volatile AuUInt32 uAtomicSleeping {}; + private: + + auline bool TryLock2() + { + for (AU_ITERATE_N(i, AuUInt(1u) << AuUInt(Threading::GetSpinCountTimeout()))) + { + #if defined(AURORA_ARCH_X86) || defined(AURORA_ARCH_X64) + _mm_pause(); + #else + Threading::ContextYield(); + #endif + + auto old = this->uAtomicState; + if ((old != 0 && AuAtomicCompareExchange(&this->uAtomicState, old - 1, old) == old)) + { + return true; + } + } + + return false; + } + + auline bool SleepOne(AuUInt64 qwTimeout) + { + static const AuUInt32 kRef { 0 }; + + while (!TryLock2()) + { + bool bStatus {}; + + bStatus = WaitOnAddressSteady((void *)&this->uAtomicState, &kRef, sizeof(kRef), qwTimeout); + + if (!bStatus) + { + return TryLock2(); + } + } + + return true; + } + }; +} \ No newline at end of file diff --git a/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp b/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp index 646a91da..069b2735 100644 --- a/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp +++ b/Include/Aurora/Threading/Waitables/FutexSemaphoreWaitable.hpp @@ -81,7 +81,7 @@ namespace Aurora::Threading::Waitables if (auto uSleeping = this->uAtomicSleeping) { - WakeNOnAddress(&this->uAtomicState, uSleeping); + WakeNOnAddress((const void *)&this->uAtomicState, uSleeping); } } @@ -92,7 +92,7 @@ namespace Aurora::Threading::Waitables while (!TryLock()) { AuAtomicAdd(&this->uAtomicSleeping, 1u); - WaitOnAddress(&this->uAtomicState, &kRef, sizeof(kRef), 0); + WaitOnAddress((void *)&this->uAtomicState, &kRef, sizeof(kRef), 0); AuAtomicSub(&this->uAtomicSleeping, 1u); } } @@ -118,7 +118,7 @@ namespace Aurora::Threading::Waitables 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) @@ -139,7 +139,7 @@ namespace Aurora::Threading::Waitables 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) @@ -151,7 +151,7 @@ namespace Aurora::Threading::Waitables return true; } - AuUInt32 uAtomicState {}; - AuUInt32 uAtomicSleeping {}; + volatile AuUInt32 uAtomicState {}; + volatile AuUInt32 uAtomicSleeping {}; }; } \ No newline at end of file diff --git a/Include/Aurora/Threading/Waitables/Waitables.hpp b/Include/Aurora/Threading/Waitables/Waitables.hpp index 80efe2cd..b58ba28f 100644 --- a/Include/Aurora/Threading/Waitables/Waitables.hpp +++ b/Include/Aurora/Threading/Waitables/Waitables.hpp @@ -10,4 +10,5 @@ #include "CBWaitable.hpp" #include "BooleanWaitable.hpp" #include "FutexWaitable.hpp" -#include "FutexSemaphoreWaitable.hpp" \ No newline at end of file +#include "FutexSemaphoreWaitable.hpp" +#include "FutexCondWaitable.hpp" \ No newline at end of file