AuroraRuntime/Source/Threading/Primitives/AuConditionVariable.Generic.cpp

95 lines
2.6 KiB
C++

/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuConditionVariable.Generic.cpp
Date: 2021-6-14
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include <Source/Threading/AuWaitFor.hpp>
#include "AuConditionVariable.Generic.hpp"
#if defined(_AURUNTIME_GENERICCV)
namespace Aurora::Threading::Primitives
{
ConditionVariableImpl::ConditionVariableImpl(const AuSPtr<IConditionMutex> &mutex) : mutex_(AuDynamicCast<ConditionMutexImpl>(mutex))
{
}
AuSPtr<IConditionMutex> ConditionVariableImpl::GetMutex()
{
return mutex_;
}
bool ConditionVariableImpl::WaitForSignal(AuUInt32 timeout)
{
// yield then wake up spuriously - this is should be illegal, but works well enough as a place holder
mutex_->Unlock();
for (int i = 0; i < 20; i++)
{
YieldToOtherThread();
}
mutex_->Lock();
/**
TODO: A more technically competent solution may be more sophisticated than anything proposed here,
but the following seems good enough.
It's same thing without the spurious wake ups and hopefully scalable timeout-relative yielding
wait ->
waiting_++
WaitFor([]() {
auto old = signals_.load(std::memory_order_relaxed);
return old != 0 && signals_.compare_exchange_strong(old, old - 1);
})
*/
return true;
}
void ConditionVariableImpl::Signal()
{
signals_++;
waiting_--;
}
void ConditionVariableImpl::Broadcast()
{
auto initwaiting = waiting_.load(std::memory_order_relaxed);
if (initwaiting < 0) return;
signals_ += initwaiting;
#if 0
auto old = initwaiting;
if (!old) return;
while (!(waiting_.compare_exchange_strong(old, old - initwaiting)))
{
old = waiting_.load(std::memory_order_relaxed);
if (!old) return;
}
#else
waiting_ -= initwaiting;
// is it possible to go negative on waiters? yes!
// is it a big deal? well, no actually
// the only way this can happen is if we have above 0 signals and no threads waiting
// it should sort itself out
#endif
}
AUKN_SYM IConditionVariable *ConditionVariableNew(const AuSPtr<IConditionMutex> &mutex)
{
return _new ConditionVariableImpl(mutex);
}
AUKN_SYM void ConditionVariableRelease(IConditionVariable *mutex)
{
AuSafeDelete<ConditionVariableImpl *>(mutex);
}
}
#endif