[+] 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 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<typename T, bool bIsStatic = false>
|
||||
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)
|
||||
{
|
||||
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 {};
|
||||
};
|
||||
}
|
@ -11,3 +11,4 @@
|
||||
#include "BooleanWaitable.hpp"
|
||||
#include "FutexWaitable.hpp"
|
||||
#include "FutexSemaphoreWaitable.hpp"
|
||||
#include "FutexCondWaitable.hpp"
|
Loading…
Reference in New Issue
Block a user