AuroraRuntime/Source/Threading/Primitives/AuConditionEx.cpp

171 lines
4.4 KiB
C++
Raw Normal View History

2021-06-27 21:25:29 +00:00
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
2022-11-17 07:46:07 +00:00
File: AuConditionEx.cpp
2021-06-27 21:25:29 +00:00
Date: 2021-6-12
Author: Reece
***/
2021-09-30 14:57:41 +00:00
#include <Source/RuntimeInternal.hpp>
2022-11-17 07:46:07 +00:00
#include "AuConditionEx.hpp"
#include "AuSemaphore.Generic.hpp"
2021-06-27 21:25:29 +00:00
namespace Aurora::Threading::Primitives
{
2022-06-01 21:49:38 +00:00
struct SemaphoreConditionVariableImpl : ConditionEx
2021-06-27 21:25:29 +00:00
{
SemaphoreConditionVariableImpl();
void WaitForSignal(IWaitable *pWaitable) override;
void WaitForSignal(const AuSPtr<IWaitable> &pWaitable) override;
2021-06-27 21:25:29 +00:00
void WaitForSignal() override;
bool WaitForSignalNS(AuUInt64 uRelativeNanoseconds) override;
bool WaitForSignalNS(IWaitable *waitable, AuUInt64 uRelativeNanoseconds) override;
bool WaitForSignalNS(const AuSPtr<IWaitable> &waitable, AuUInt64 uRelativeNanoseconds) override;
2021-06-27 21:25:29 +00:00
void Signal() override;
void Broadcast() override;
private:
SemaphoreImpl s_;
AuUInt32 uWaiters_;
2021-06-27 21:25:29 +00:00
};
2022-11-17 07:46:07 +00:00
SemaphoreConditionVariableImpl::SemaphoreConditionVariableImpl() :
s_(0),
uWaiters_(0)
{
}
bool SemaphoreConditionVariableImpl::WaitForSignalNS(AuUInt64 uRelativeNanoseconds)
{
return WaitForSignalNS(nullptr, uRelativeNanoseconds);
}
bool SemaphoreConditionVariableImpl::WaitForSignalNS(IWaitable *pWaitable, AuUInt64 uRelativeNanoseconds)
2021-06-27 21:25:29 +00:00
{
return WaitForSignalNS(pWaitable ? AuUnsafeRaiiToShared(pWaitable) : AuSPtr<IWaitable> {},
uRelativeNanoseconds);
}
bool SemaphoreConditionVariableImpl::WaitForSignalNS(const AuSPtr<IWaitable> &pWaitable,
AuUInt64 uRelativeNanoseconds)
{
AuAtomicAdd(&this->uWaiters_, 1u);
if (pWaitable)
{
pWaitable->Unlock();
}
auto bSuccess = this->s_.LockNS(uRelativeNanoseconds);
if (!bSuccess)
{
auto uWaiters = this->uWaiters_;
auto uWaitCount = 1;
while (AuAtomicCompareExchange(&this->uWaiters_, uWaiters - uWaitCount, uWaiters) != uWaiters)
{
uWaiters = this->uWaiters_;
2021-06-27 21:25:29 +00:00
if (uWaiters == 0)
{
break;
}
}
}
if (pWaitable)
{
pWaitable->Lock();
}
return bSuccess;
2021-06-27 21:25:29 +00:00
}
void SemaphoreConditionVariableImpl::WaitForSignal(IWaitable *pWaitable)
{
2022-11-17 07:46:07 +00:00
return WaitForSignal(AuUnsafeRaiiToShared(pWaitable));
}
void SemaphoreConditionVariableImpl::WaitForSignal(const AuSPtr<IWaitable> &pWaitable)
2021-06-27 21:25:29 +00:00
{
AuAtomicAdd(&this->uWaiters_, 1u);
2021-06-27 21:25:29 +00:00
2022-11-17 07:46:07 +00:00
if (pWaitable)
2021-06-27 21:25:29 +00:00
{
2022-11-17 07:46:07 +00:00
pWaitable->Unlock();
2021-06-27 21:25:29 +00:00
}
2022-11-17 07:46:07 +00:00
this->s_.Lock();
2021-06-27 21:25:29 +00:00
2022-11-17 07:46:07 +00:00
if (pWaitable)
2021-06-27 21:25:29 +00:00
{
2022-11-17 07:46:07 +00:00
pWaitable->Lock();
2021-06-27 21:25:29 +00:00
}
}
void SemaphoreConditionVariableImpl::WaitForSignal()
{
WaitForSignal(nullptr);
}
void SemaphoreConditionVariableImpl::Signal()
{
AuUInt32 uWaitCount {};
AuUInt32 uWaiters {};
uWaiters = this->uWaiters_;
if (uWaiters > 0)
2021-06-27 21:25:29 +00:00
{
this->s_.Unlock();
uWaitCount = 1;
}
while (AuAtomicCompareExchange(&this->uWaiters_, uWaiters - uWaitCount, uWaiters) != uWaiters)
{
uWaiters = this->uWaiters_;
if (uWaiters == 0)
{
return;
}
2021-06-27 21:25:29 +00:00
}
}
void SemaphoreConditionVariableImpl::Broadcast()
{
AuUInt32 uWaitCount {};
AuUInt32 uWaiters {};
uWaiters = this->uWaiters_;
if (uWaiters > 0)
2021-06-27 21:25:29 +00:00
{
this->s_.Unlock(uWaiters);
uWaitCount = uWaiters;
}
while (AuAtomicCompareExchange(&this->uWaiters_, uWaiters - uWaitCount, uWaiters) != uWaiters)
{
uWaiters = this->uWaiters_;
if (uWaiters <= uWaitCount)
{
uWaitCount = uWaiters;
}
2021-06-27 21:25:29 +00:00
}
}
AUKN_SYM ConditionEx *FlexibleConditionVariableNew()
2021-06-27 21:25:29 +00:00
{
return _new SemaphoreConditionVariableImpl();
}
AUKN_SYM void FlexibleConditionVariableRelease(ConditionEx *pCVEx)
2021-06-27 21:25:29 +00:00
{
2022-11-17 07:46:07 +00:00
AuSafeDelete<SemaphoreConditionVariableImpl *>(pCVEx);
2021-06-27 21:25:29 +00:00
}
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, FlexibleConditionVariable, SemaphoreConditionVariableImpl)
2021-06-27 21:25:29 +00:00
}