From f2e3ceef99e76c38ebd29051743318a4ca08b745 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Sun, 30 Jun 2024 05:34:14 +0100 Subject: [PATCH] [+] Au[Futex]Countdown --- Include/Aurora/RuntimeAliases.hpp | 2 + .../Threading/Waitables/FutexCountdown.hpp | 193 ++++++++++++++++++ .../Aurora/Threading/Waitables/Waitables.hpp | 3 +- 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 Include/Aurora/Threading/Waitables/FutexCountdown.hpp diff --git a/Include/Aurora/RuntimeAliases.hpp b/Include/Aurora/RuntimeAliases.hpp index 125696c5..471df854 100644 --- a/Include/Aurora/RuntimeAliases.hpp +++ b/Include/Aurora/RuntimeAliases.hpp @@ -103,8 +103,10 @@ using AuFutexSemaphore = AuThreading::Waitables::FutexSemaphoreWaitable; using AuFutexCond = AuThreading::Waitables::FutexCondWaitable; using AuFutexCondition = AuThreading::Waitables::FutexCondWaitable; using AuFutexBarrier = AuThreading::Waitables::FutexBarrier; +using AuFutexCountdown = AuThreading::Waitables::FutexCountdown; using AuBarrier = AuThreading::Waitables::FutexBarrier; +using AuCountdown = AuThreading::Waitables::FutexCountdown; using AuInitOnce = AuThreading::InitOnce; using AuInitOnceSmall = __audetail::InitOnceABI; diff --git a/Include/Aurora/Threading/Waitables/FutexCountdown.hpp b/Include/Aurora/Threading/Waitables/FutexCountdown.hpp new file mode 100644 index 00000000..553a2f12 --- /dev/null +++ b/Include/Aurora/Threading/Waitables/FutexCountdown.hpp @@ -0,0 +1,193 @@ +/*** + Copyright (C) 2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: FutexCountdown.hpp + Date: 2024-06-30 + Author: Reece +***/ +#pragma once + +#include "../WakeOnAddress.hpp" +#include "../SpinTime.hpp" +#include "_.inl" + +namespace Aurora::Threading::Waitables +{ + struct FutexCountdown final : IWaitable + { + inline constexpr FutexCountdown() + {} + + inline constexpr FutexCountdown(AuUInt32 uUsers) : + uAtomicState(uUsers) + { } + + inline constexpr FutexCountdown(const FutexCountdown &that) : + uAtomicState(that.uAtomicState) + { } + + inline constexpr FutexCountdown(FutexCountdown &&that) : + uAtomicState(that.uAtomicState) + { } + + AURT_WAITABLE_COPY_OPERATORS(FutexCountdown) + + inline auline void AddUser() + { + AuAtomicAdd(&this->uAtomicState, 1u); + } + + inline auline void AddUsers(AuUInt32 uCount) + { + AuAtomicAdd(&this->uAtomicState, uCount); + } + + inline auline void DecrementUser() + { + if (!AuAtomicSub(&this->uAtomicState, 1u)) + { + if (AuAtomicLoad(&this->uAtomicSleeping)) + { + WakeAllOnAddress((const void *)&this->uAtomicState); + } + } + } + + inline auline void DecrementUsers(AuUInt32 uCount) + { + if (!AuAtomicSub(&this->uAtomicState, uCount)) + { + if (AuAtomicLoad(&this->uAtomicSleeping)) + { + WakeAllOnAddress((const void *)&this->uAtomicState); + } + } + } + + inline auline bool TryLockNoSpin() + { + return AuAtomicLoad(&this->uAtomicState) == 0; + } + + inline bool TryLock() override + { + static const AuUInt32 kRef { 0 }; + + if (this->TryLockNoSpin()) + { + return true; + } + + return TryWaitOnAddressSpecial(EWaitMethod::eEqual, + (const void *)&this->uAtomicState, + &kRef, + sizeof(kRef)); + } + + inline bool HasOSHandle(AuMach &mach) override + { + return false; + } + + inline bool HasLockImplementation() override + { + return true; + } + + inline void Unlock() override + { + + } + + inline void Lock() override + { + static const AuUInt32 kRef { 0 }; + + if (this->TryLock()) + { + return; + } + + while (!this->TryLockNoSpin()) + { + AuAtomicAdd(&this->uAtomicSleeping, 1u); + WaitOnAddressSpecial(EWaitMethod::eEqual, (const void *)&this->uAtomicState, &kRef, sizeof(kRef), 0, true); + AuAtomicSub(&this->uAtomicSleeping, 1u); + } + } + + inline bool LockMS(AuUInt64 qwTimeout) override + { + return LockNS(AuMSToNS(qwTimeout)); + } + + inline bool LockAbsMS(AuUInt64 qwTimeout) override + { + return LockAbsNS(AuMSToNS(qwTimeout)); + } + + inline bool LockNS(AuUInt64 qwTimeout) override + { + static const AuUInt32 kRef { 0 }; + + if (this->TryLockNoSpin()) + { + return true; + } + + auto qwEndTime = qwTimeout ? + Time::SteadyClockNS() + qwTimeout : + 0; + + if (this->TryLock()) + { + return true; + } + + while (!this->TryLockNoSpin()) + { + bool bStatus {}; + + AuAtomicAdd(&this->uAtomicSleeping, 1u); + bStatus = WaitOnAddressSpecialSteady(EWaitMethod::eEqual, (const void *)&this->uAtomicState, &kRef, sizeof(kRef), qwEndTime, true); + AuAtomicSub(&this->uAtomicSleeping, 1u); + + if (!bStatus) + { + return this->TryLock(); + } + } + + return true; + } + + inline bool LockAbsNS(AuUInt64 qwTimeoutAbs) override + { + static const AuUInt32 kRef { 0 }; + + if (this->TryLockNoSpin()) + { + return true; + } + + while (!this->TryLockNoSpin()) + { + bool bStatus {}; + + AuAtomicAdd(&this->uAtomicSleeping, 1u); + bStatus = WaitOnAddressSpecialSteady(EWaitMethod::eEqual, (const void *)&this->uAtomicState, &kRef, sizeof(kRef), qwTimeoutAbs, true); + AuAtomicSub(&this->uAtomicSleeping, 1u); + + if (!bStatus) + { + return this->TryLock(); + } + } + + return true; + } + + AuAUInt32 uAtomicState {}; + AuAUInt32 uAtomicSleeping {}; + }; +} \ No newline at end of file diff --git a/Include/Aurora/Threading/Waitables/Waitables.hpp b/Include/Aurora/Threading/Waitables/Waitables.hpp index 6cb40a58..4f6be84f 100644 --- a/Include/Aurora/Threading/Waitables/Waitables.hpp +++ b/Include/Aurora/Threading/Waitables/Waitables.hpp @@ -13,4 +13,5 @@ #include "FutexWaitable.hpp" #include "FutexSemaphoreWaitable.hpp" #include "FutexCondWaitable.hpp" -#include "FutexBarrier.hpp" \ No newline at end of file +#include "FutexBarrier.hpp" +#include "FutexCountdown.hpp" \ No newline at end of file