AuroraRuntime/Source/Threading/Primitives/AuConditionEx.cpp

178 lines
4.6 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"
2024-04-13 21:49:05 +00:00
#include "SMTYield.hpp" // for: while_bc
2021-06-27 21:25:29 +00:00
namespace Aurora::Threading::Primitives
{
struct SemaphoreConditionVariableImpl :
IFlexibleConditionVariable
2021-06-27 21:25:29 +00:00
{
SemaphoreConditionVariableImpl();
void WaitForSignal(IWaitable *pWaitable) override;
2021-06-27 21:25:29 +00:00
void WaitForSignal() override;
bool WaitForSignalNS(AuUInt64 uRelativeNanoseconds) override;
bool WaitForSignalNS(IWaitable *pWaitable, AuUInt64 uRelativeNanoseconds) override;
2023-11-29 06:08:09 +00:00
bool WaitForSignalAbsNS(AuUInt64 uAbsNanoseconds) override;
bool WaitForSignalAbsNS(IWaitable *pWaitable, AuUInt64 uAbsNanoseconds) override;
2023-11-29 06:08:09 +00:00
2021-06-27 21:25:29 +00:00
void Signal() override;
void Broadcast() override;
private:
SemaphoreImpl s_;
2023-09-02 03:55:43 +00:00
AuAUInt32 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::WaitForSignalAbsNS(IWaitable *pWaitable,
AuUInt64 uNanoseconds)
{
AuAtomicAdd(&this->uWaiters_, 1u);
if (pWaitable)
{
pWaitable->Unlock();
}
auto bSuccess = this->s_.LockAbsNS(uNanoseconds);
if (!bSuccess)
{
auto uWaiters = this->uWaiters_;
auto uWaitCount = 1;
while (uWaiters &&
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
}
bool SemaphoreConditionVariableImpl::WaitForSignalNS(IWaitable *pWaitable,
2023-11-29 06:08:09 +00:00
AuUInt64 uAbsNanoseconds)
{
2023-11-29 06:08:09 +00:00
return this->WaitForSignalAbsNS(pWaitable,
uAbsNanoseconds ? AuTime::SteadyClockNS() + uAbsNanoseconds : 0);
}
void SemaphoreConditionVariableImpl::WaitForSignal(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);
}
2023-11-29 06:08:09 +00:00
bool SemaphoreConditionVariableImpl::WaitForSignalAbsNS(AuUInt64 uAbsNanoseconds)
{
return this->WaitForSignalAbsNS({}, uAbsNanoseconds);
}
2021-06-27 21:25:29 +00:00
void SemaphoreConditionVariableImpl::Signal()
{
AuUInt32 uWaitCount {};
AuUInt32 uWaiters {};
uWaiters = AuAtomicLoad(&this->uWaiters_);
2023-08-26 17:46:00 +00:00
if (uWaiters == 0)
2021-06-27 21:25:29 +00:00
{
2023-08-26 17:46:00 +00:00
return;
}
2023-08-26 17:46:00 +00:00
this->s_.Unlock();
while (uWaiters &&
2023-08-26 17:46:00 +00:00
AuAtomicCompareExchange(&this->uWaiters_, uWaiters - 1u, uWaiters) != uWaiters)
{
uWaiters = this->uWaiters_;
if (uWaiters == 0)
{
return;
}
2021-06-27 21:25:29 +00:00
}
}
void SemaphoreConditionVariableImpl::Broadcast()
{
AuUInt32 uWaitCount {};
AuUInt32 uWaiters {};
2024-04-13 21:49:05 +00:00
while_bc ((uWaiters = AuAtomicLoad(&this->uWaiters_)))
2021-06-27 21:25:29 +00:00
{
this->s_.Unlock(uWaiters);
uWaitCount = uWaiters;
while (uWaiters &&
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 IFlexibleConditionVariable *FlexibleConditionVariableNew()
2021-06-27 21:25:29 +00:00
{
return _new SemaphoreConditionVariableImpl();
}
AUKN_SYM void FlexibleConditionVariableRelease(IFlexibleConditionVariable *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
}