[+] FutexCondWaitable

[+] (shorthand) AuMutex
[+] (shorthand) AuSemaphore
[+] (shorthand) AuRWRenterableLock
[+] (shorthand) AuRenterableMutex
[+] (shorthand) AuRWLock
[+] (shorthand) AuCond
[+] (shorthand) AuCondMutex
[+] (shorthand) AuSpinLock
[+] (shorthand) AuFutexCond
This commit is contained in:
Reece Wilson 2023-08-19 22:25:31 +01:00
parent fd643b81ce
commit 7ce89a143f
4 changed files with 230 additions and 7 deletions

View File

@ -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>;

View 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;
}
};
}

View File

@ -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 {};
};
}

View File

@ -11,3 +11,4 @@
#include "BooleanWaitable.hpp"
#include "FutexWaitable.hpp"
#include "FutexSemaphoreWaitable.hpp"
#include "FutexCondWaitable.hpp"