AuroraRuntime/Source/Threading/Primitives/AuConditionEx.cpp

103 lines
2.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 "AuMutex.Generic.hpp"
#include "AuSemaphore.Generic.hpp"
2021-06-27 21:25:29 +00:00
namespace Aurora::Threading::Primitives
{
// Implementing Condition Variables with Semaphores, Andrew Birrell, MSFT
// Subsitute semaphore count = 1 with a spinlock and...
2022-06-01 21:49:38 +00:00
struct SemaphoreConditionVariableImpl : ConditionEx
2021-06-27 21:25:29 +00:00
{
SemaphoreConditionVariableImpl();
2022-11-17 07:46:07 +00:00
void WaitForSignal(Aurora::Threading::IWaitable *pWaitable) override;
void WaitForSignal(const AuSPtr<Threading::IWaitable> &pWaitable) override;
2021-06-27 21:25:29 +00:00
void WaitForSignal() override;
void Signal() override;
void Broadcast() override;
private:
std::atomic<AuUInt> waiters_;
Semaphore s_, h_;
SpinLock x_;
};
2022-11-17 07:46:07 +00:00
SemaphoreConditionVariableImpl::SemaphoreConditionVariableImpl() :
s_(0),
h_(0)
2021-06-27 21:25:29 +00:00
{
}
2022-11-17 07:46:07 +00:00
void SemaphoreConditionVariableImpl::WaitForSignal(Aurora::Threading::IWaitable *pWaitable)
{
2022-11-17 07:46:07 +00:00
return WaitForSignal(AuUnsafeRaiiToShared(pWaitable));
}
2022-11-17 07:46:07 +00:00
void SemaphoreConditionVariableImpl::WaitForSignal(const AuSPtr<Threading::IWaitable> &pWaitable)
2021-06-27 21:25:29 +00:00
{
2022-11-17 07:46:07 +00:00
this->x_.Lock();
this->waiters_++;
this->x_.Unlock();
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();
this->h_.Unlock();
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()
{
2022-11-17 07:46:07 +00:00
this->x_.Lock();
if (this->waiters_ > 0)
2021-06-27 21:25:29 +00:00
{
2022-11-17 07:46:07 +00:00
this->waiters_--;
this->s_.Unlock(); // 1 may pass
this->h_.Lock(); // finish operation - wait for the alive signal back
2021-06-27 21:25:29 +00:00
}
2022-11-17 07:46:07 +00:00
this->x_.Unlock();
2021-06-27 21:25:29 +00:00
}
void SemaphoreConditionVariableImpl::Broadcast()
{
2022-11-17 07:46:07 +00:00
this->x_.Lock();
this->s_.Unlock(this->waiters_); // all may pass at once
for (auto i = 0; i < this->waiters_; i++)
2021-06-27 21:25:29 +00:00
{
2022-11-17 07:46:07 +00:00
this->h_.Lock(); // finish operation - wait for the alive signal back
2021-06-27 21:25:29 +00:00
}
2022-11-17 07:46:07 +00:00
this->waiters_ = 0;
this->x_.Unlock();
2021-06-27 21:25:29 +00:00
}
AUKN_SYM ConditionEx *FeaturefulConditionNew()
{
return _new SemaphoreConditionVariableImpl();
}
2022-11-17 07:46:07 +00:00
AUKN_SYM void FeaturefulConditionRelease(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
}
}