[+] AuInitOnce

This commit is contained in:
Reece Wilson 2023-09-17 04:40:15 +01:00
parent 0de153dfe3
commit afa2cb5944
3 changed files with 163 additions and 2 deletions

View File

@ -130,8 +130,8 @@ using AuMemoryViewStreamWrite = AuMemory::MemoryViewStreamWrite;
using AuMutex = AuThreadPrimitives::Mutex;
using AuSemaphore = AuThreadPrimitives::Semaphore;
using AuRWRenterableLock = AuThreadPrimitives::RWRenterableLock;
using AuRenterableMutex = AuThreadPrimitives::CriticalSection;
using AuRWRenterableLock = AuThreadPrimitives::RWRenterableLock;
using AuRWLock = AuThreadPrimitives::RWLock;
using AuCond = AuThreadPrimitives::ConditionVariable;
using AuCondMutex = AuThreadPrimitives::ConditionMutex;
@ -143,6 +143,8 @@ using AuFutexMutex = AuThreading::Waitables::FutexWaitable;
using AuFutexSemaphore = AuThreading::Waitables::FutexSemaphoreWaitable;
using AuFutexCond = AuThreading::Waitables::FutexCondWaitable;
using AuInitOnce = AuThreading::InitOnce;
template<typename T, bool bIsStatic = false>
using AuTLSVariable = AuThreads::TLSVariable<T, bIsStatic>;

View File

@ -0,0 +1,157 @@
/***
Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: InitOnce.hpp
Date: 2023-09-17
Author: Reece
***/
#pragma once
namespace Aurora::Threading
{
struct InitOnce :
private IWaitable
{
inline bool IsUninitialized()
{
return (AuAtomicLoad(&this->uToken_) & 1) == 0;
}
inline bool IsReady()
{
return (AuAtomicLoad(&this->uToken_) & 2) != 0;
}
inline bool TrySet()
{
if (AuAtomicTestAndSet(&this->uToken_, 0) == 0)
{
this->Finish();
return true;
}
else
{
return false;
}
}
template <typename Callable>
bool TryInit(const Callable &callback)
{
if (AuAtomicTestAndSet(&this->uToken_, 0) == 0)
{
callback();
this->Finish();
return true;
}
else
{
return false;
}
}
template <typename Callable>
void Call(const Callable &callback)
{
if (this->TryInit(callback))
{
return;
}
if (this->IsReady())
{
return;
}
this->Lock();
}
inline void Wait()
{
this->Lock();
}
inline IWaitable *ToBarrier()
{
return this;
}
protected:
inline void Finish()
{
AuAtomicSet(&this->uToken_, 1);
this->Wakeup();
}
// barrier impl:
inline void Wakeup()
{
if (auto uSleepers = AuAtomicLoad(&this->uSleepers_))
{
WakeNOnAddress((const void *)&this->uToken_, uSleepers);
}
}
inline bool HasOSHandle(AuMach &mach)
{
return false;
}
inline bool HasLockImplementation()
{
return true;
}
inline void Lock()
{
this->LockAbsNS(0);
}
inline bool LockNS(AuUInt64 qwTimeoutInNs)
{
if (this->IsReady())
{
return true;
}
return IWaitable::LockNS(qwTimeoutInNs);
}
inline bool LockAbsNS(AuUInt64 qwAbsTimeoutInNs /* = 0, infinity*/)
{
auto uCurrent = AuAtomicLoad(&this->uToken_);
while ((uCurrent & 2) == 0)
{
AuAtomicAdd(&this->uSleepers_, 1u);
bool bRet = WaitOnAddressSteady((const void *)&this->uToken_, &uCurrent, sizeof(uCurrent), qwAbsTimeoutInNs);
AuAtomicSub(&this->uSleepers_, 1u);
if (!bRet)
{
return this->IsReady();
}
uCurrent = AuAtomicLoad(&this->uToken_);
}
return true;
}
inline bool TryLock()
{
return this->IsReady();
}
inline void Unlock()
{
}
private:
AuAUInt32 uToken_ {};
AuAUInt32 uSleepers_ {};
};
}

View File

@ -26,4 +26,6 @@ namespace Aurora::Threading
#include "SpinTime.hpp"
#include "Threads/Threads.hpp"
#include "Threads/Threads.hpp"
#include "InitOnce.hpp"