95 lines
2.6 KiB
C++
95 lines
2.6 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: ConditionVariable.Generic.cpp
|
|
Date: 2021-6-14
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "../WaitFor.hpp"
|
|
#include "ConditionVariable.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 |