AuroraRuntime/Source/Threading/Primitives/AuConditionEx.cpp

103 lines
2.6 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuConditionEx.cpp
Date: 2021-6-12
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuConditionEx.hpp"
#include "AuMutex.Generic.hpp"
#include "AuSemaphore.Generic.hpp"
namespace Aurora::Threading::Primitives
{
// Implementing Condition Variables with Semaphores, Andrew Birrell, MSFT
// Subsitute semaphore count = 1 with a spinlock and...
struct SemaphoreConditionVariableImpl : ConditionEx
{
SemaphoreConditionVariableImpl();
void WaitForSignal(Aurora::Threading::IWaitable *pWaitable) override;
void WaitForSignal(const AuSPtr<Threading::IWaitable> &pWaitable) override;
void WaitForSignal() override;
void Signal() override;
void Broadcast() override;
private:
std::atomic<AuUInt> waiters_;
Semaphore s_, h_;
SpinLock x_;
};
SemaphoreConditionVariableImpl::SemaphoreConditionVariableImpl() :
s_(0),
h_(0)
{
}
void SemaphoreConditionVariableImpl::WaitForSignal(Aurora::Threading::IWaitable *pWaitable)
{
return WaitForSignal(AuUnsafeRaiiToShared(pWaitable));
}
void SemaphoreConditionVariableImpl::WaitForSignal(const AuSPtr<Threading::IWaitable> &pWaitable)
{
this->x_.Lock();
this->waiters_++;
this->x_.Unlock();
if (pWaitable)
{
pWaitable->Unlock();
}
this->s_.Lock();
this->h_.Unlock();
if (pWaitable)
{
pWaitable->Lock();
}
}
void SemaphoreConditionVariableImpl::WaitForSignal()
{
WaitForSignal(nullptr);
}
void SemaphoreConditionVariableImpl::Signal()
{
this->x_.Lock();
if (this->waiters_ > 0)
{
this->waiters_--;
this->s_.Unlock(); // 1 may pass
this->h_.Lock(); // finish operation - wait for the alive signal back
}
this->x_.Unlock();
}
void SemaphoreConditionVariableImpl::Broadcast()
{
this->x_.Lock();
this->s_.Unlock(this->waiters_); // all may pass at once
for (auto i = 0; i < this->waiters_; i++)
{
this->h_.Lock(); // finish operation - wait for the alive signal back
}
this->waiters_ = 0;
this->x_.Unlock();
}
AUKN_SYM ConditionEx *FeaturefulConditionNew()
{
return _new SemaphoreConditionVariableImpl();
}
AUKN_SYM void FeaturefulConditionRelease(ConditionEx *pCVEx)
{
AuSafeDelete<SemaphoreConditionVariableImpl *>(pCVEx);
}
}