AuroraRuntime/Source/Threading/Primitives/ConditionEx.cpp

96 lines
2.3 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ConditionEx.cpp
Date: 2021-6-12
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "ConditionEx.hpp"
#include "Mutex.Generic.hpp"
#include "Semaphore.Generic.hpp"
namespace Aurora::Threading::Primitives
{
// Implementing Condition Variables with Semaphores, Andrew Birrell, MSFT
// Subsitute semaphore count = 1 with a spinlock and...
class SemaphoreConditionVariableImpl : public ConditionEx
{
public:
SemaphoreConditionVariableImpl();
void WaitForSignal(Aurora::Threading::IWaitable *waitable) 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 *waitable)
{
x_.Lock();
waiters_++;
x_.Unlock();
if (waitable)
{
waitable->Unlock();
}
s_.Lock();
h_.Unlock();
if (waitable)
{
waitable->Lock();
}
}
void SemaphoreConditionVariableImpl::WaitForSignal()
{
WaitForSignal(nullptr);
}
void SemaphoreConditionVariableImpl::Signal()
{
x_.Lock();
if (waiters_ > 0)
{
waiters_--;
s_.Unlock(); // 1 may pass
h_.Lock(); // finish operation - wait for the alive signal back
}
x_.Unlock();
}
void SemaphoreConditionVariableImpl::Broadcast()
{
x_.Lock();
s_.Unlock(waiters_); // all may pass at once
for (auto i = 0; i < waiters_; i++)
{
h_.Lock(); // finish operation - wait for the alive signal back
}
waiters_ = 0;
x_.Unlock();
}
AUKN_SYM ConditionEx *FeaturefulConditionNew()
{
return _new SemaphoreConditionVariableImpl();
}
AUKN_SYM void FeaturefulConditionRelease(ConditionEx *semaphore)
{
SafeDelete<SemaphoreConditionVariableImpl *>(semaphore);
}
}