[+] FutexCondWaitable
[+] (shorthand) AuMutex [+] (shorthand) AuSemaphore [+] (shorthand) AuRWRenterableLock [+] (shorthand) AuRenterableMutex [+] (shorthand) AuRWLock [+] (shorthand) AuCond [+] (shorthand) AuCondMutex [+] (shorthand) AuSpinLock [+] (shorthand) AuFutexCond
This commit is contained in:
parent
fd643b81ce
commit
7ce89a143f
@ -127,8 +127,19 @@ using AuMemoryViewWrite = AuMemory::MemoryViewWrite;
|
|||||||
using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead;
|
using AuMemoryViewStreamRead = AuMemory::MemoryViewStreamRead;
|
||||||
using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite;
|
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 AuFutexMutex = AuThreading::Waitables::FutexWaitable;
|
||||||
using AuFutexSemaphore = AuThreading::Waitables::FutexSemaphoreWaitable;
|
using AuFutexSemaphore = AuThreading::Waitables::FutexSemaphoreWaitable;
|
||||||
|
using AuFutexCond = AuThreading::Waitables::FutexCondWaitable;
|
||||||
|
|
||||||
template<typename T, bool bIsStatic = false>
|
template<typename T, bool bIsStatic = false>
|
||||||
using AuTLSVariable = AuThreads::TLSVariable<T, bIsStatic>;
|
using AuTLSVariable = AuThreads::TLSVariable<T, bIsStatic>;
|
||||||
|
211
Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp
Normal file
211
Include/Aurora/Threading/Waitables/FutexCondWaitable.hpp
Normal file
@ -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 <class T>
|
||||||
|
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 <class T>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -81,7 +81,7 @@ namespace Aurora::Threading::Waitables
|
|||||||
|
|
||||||
if (auto uSleeping = this->uAtomicSleeping)
|
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())
|
while (!TryLock())
|
||||||
{
|
{
|
||||||
AuAtomicAdd(&this->uAtomicSleeping, 1u);
|
AuAtomicAdd(&this->uAtomicSleeping, 1u);
|
||||||
WaitOnAddress(&this->uAtomicState, &kRef, sizeof(kRef), 0);
|
WaitOnAddress((void *)&this->uAtomicState, &kRef, sizeof(kRef), 0);
|
||||||
AuAtomicSub(&this->uAtomicSleeping, 1u);
|
AuAtomicSub(&this->uAtomicSleeping, 1u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ namespace Aurora::Threading::Waitables
|
|||||||
bool bStatus {};
|
bool bStatus {};
|
||||||
|
|
||||||
AuAtomicAdd(&this->uAtomicSleeping, 1u);
|
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);
|
AuAtomicSub(&this->uAtomicSleeping, 1u);
|
||||||
|
|
||||||
if (!bStatus)
|
if (!bStatus)
|
||||||
@ -139,7 +139,7 @@ namespace Aurora::Threading::Waitables
|
|||||||
bool bStatus {};
|
bool bStatus {};
|
||||||
|
|
||||||
AuAtomicAdd(&this->uAtomicSleeping, 1u);
|
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);
|
AuAtomicSub(&this->uAtomicSleeping, 1u);
|
||||||
|
|
||||||
if (!bStatus)
|
if (!bStatus)
|
||||||
@ -151,7 +151,7 @@ namespace Aurora::Threading::Waitables
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuUInt32 uAtomicState {};
|
volatile AuUInt32 uAtomicState {};
|
||||||
AuUInt32 uAtomicSleeping {};
|
volatile AuUInt32 uAtomicSleeping {};
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -10,4 +10,5 @@
|
|||||||
#include "CBWaitable.hpp"
|
#include "CBWaitable.hpp"
|
||||||
#include "BooleanWaitable.hpp"
|
#include "BooleanWaitable.hpp"
|
||||||
#include "FutexWaitable.hpp"
|
#include "FutexWaitable.hpp"
|
||||||
#include "FutexSemaphoreWaitable.hpp"
|
#include "FutexSemaphoreWaitable.hpp"
|
||||||
|
#include "FutexCondWaitable.hpp"
|
Loading…
Reference in New Issue
Block a user