[*] i need sleep and i broke the core primitives

This commit is contained in:
Reece Wilson 2023-03-15 08:28:16 +00:00
parent f354a202ad
commit 49bfecee32
3 changed files with 157 additions and 68 deletions

View File

@ -46,100 +46,186 @@ namespace Aurora::Threading::Primitives
auto uEndTimeWall = AuTime::CurrentClockNS() + qwTimeout;
auto uTargetTimeNt = AuTime::ConvertTimestampNs(uEndTimeWall);
LARGE_INTEGER word;
word.QuadPart = uTargetTimeNt;
AuAtomicAdd(&this->wlist, 1u);
bRet = pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, &word) != NTSTATUS_TIMEOUT;
if (!bRet)
do
{
AuAtomicAdd(&this->expander, 1u);
LARGE_INTEGER word;
word.QuadPart = uTargetTimeNt;
if (bRet)
{
while (true)
{
auto uNow = this->wlist;
auto waiting = uNow >> 2u;
auto uNext = ((waiting + 1) << 2u) | 1;
if (AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow)
{
break;
}
}
bRet = pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, &word) != NTSTATUS_TIMEOUT;
}
else
{
LARGE_INTEGER word;
word.QuadPart = 0;
bRet = pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, &word) != NTSTATUS_TIMEOUT;
}
if (!bRet && uEndTimeSteady <= AuTime::SteadyClockNS())
{
while (true)
{
auto uNow = this->wlist;
auto waiting = (uNow >> 2u) - 1u;
auto uNext = waiting << 2u;
if (AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow)
{
this->mutex_->Lock();
return false;
}
}
}
else
{
if (!CheckOut(bRet))
{
continue;
}
this->mutex_->Lock();
return bRet;
}
}
while (true);
}
else
{
AuAtomicAdd(&this->wlist, 1u);
pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, nullptr);
while (true)
{
while (true)
{
auto uNow = this->wlist;
auto waiting = uNow >> 2u;
auto uNext = ((waiting + 1) << 2u) | 1;
if (AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow)
{
break;
}
}
pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, nullptr);
if (!CheckOut(bRet))
{
continue;
}
}
this->mutex_->Lock();
return bRet;
}
}
bool ConditionVariableImpl::CheckOut(bool &bRet)
{
while (true)
{
auto uSignalNow = this->signalCount;
if (uSignalNow == 0)
{
break;
}
if (DoTryIf([=]()
{
auto uSignalNow = this->signalCount;
return AuAtomicCompareExchange(&this->signalCount, uSignalNow - 1, uSignalNow) == uSignalNow;
}))
{
auto uSignalValue = this->signalCount - 1;
while (true)
{
auto uNow = this->wlist;
auto waiting = (uNow >> 2u);
auto uNext = waiting << 2u;
if (!uSignalValue)
{
uNext |= 1;
}
if (AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow)
{
return bRet;
}
else
{
SMPPause();
}
}
}
else
{
SMPPause();
}
}
this->mutex_->Lock();
return bRet;
return false;
}
void ConditionVariableImpl::Signal()
{
auto expected = this->wlist;
AuUInt32 uExpander { this->expander };
auto original = this->wlist;
auto expected = original;
expected = expected >> 2;
if (expected || uExpander)
if (expected)
{
AuUInt32 uOffset { 0 };
while (uExpander && AuAtomicCompareExchange(&this->expander, 0u, uExpander) != uExpander)
{
SMPPause();
uExpander = this->expander;
}
if (uExpander)
{
expected = this->wlist;
while (expected && AuAtomicCompareExchange(&this->wlist, expected - uExpander, expected) != expected)
{
SMPPause();
expected = this->wlist;
}
}
expected = this->wlist;
while (expected)
{
if (AuAtomicCompareExchange(&this->wlist, expected - 1, expected) == expected)
expected--;
AuAtomicAdd(&this->signalCount, 1u);
if (AuAtomicCompareExchange(&this->wlist, (expected << 2) /*intentional clear*/, original) == original)
{
pNtReleaseKeyedEvent(gKeyedEventHandle, &this->wlist, FALSE, nullptr);
return;
}
expected = this->wlist;
original = this->wlist;
expected = original >> 2;
}
}
}
void ConditionVariableImpl::Broadcast()
{
auto expected = this->wlist;
AuUInt32 uExpander { this->expander };
auto original = this->wlist;
auto expected = original;
expected = expected >> 2;
while (expected || uExpander)
while (expected)
{
AuUInt32 uOffset { 0 };
if (uExpander && AuAtomicCompareExchange(&this->expander, 0u, uExpander) != uExpander)
{
SMPPause();
uExpander = this->expander;
expected = this->wlist;
continue;
}
if (uExpander)
{
expected = this->wlist;
while (AuAtomicCompareExchange(&this->wlist, expected - uExpander, expected) != expected)
{
SMPPause();
expected = this->wlist;
}
}
expected = this->wlist;
while (expected)
{
if (AuAtomicCompareExchange(&this->wlist, expected - 1, expected) == expected)
expected--;
AuAtomicAdd(&this->signalCount, 1u);
if (AuAtomicCompareExchange(&this->wlist, (expected << 2) /*intentional clear*/, original) == original)
{
pNtReleaseKeyedEvent(gKeyedEventHandle, &this->wlist, FALSE, nullptr);
}
expected = this->wlist;
original = this->wlist;
expected = original >> 2;
}
}
}

View File

@ -22,9 +22,11 @@ namespace Aurora::Threading::Primitives
void Signal() override;
void Broadcast() override;
bool CheckOut(bool &bRet);
private:
AuUInt32 wlist {};
AuUInt32 expander {};
AuUInt32 signalCount {};
AuSPtr<Win32ConditionMutex> mutex_;
};
}

View File

@ -161,8 +161,7 @@ namespace Aurora::Threading::Primitives
if (AuAtomicCompareExchange(&uValueRef, uValue + FAST_M_WAIT, uValue) == uValue)
{
pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL);
AuAtomicSub(&uValueRef, FAST_M_WAIT);
AuAtomicSub(&uValueRef, FAST_M_WAKE);
}
}
@ -194,15 +193,17 @@ namespace Aurora::Threading::Primitives
word.QuadPart = uTargetTimeNt;
auto uStatus = pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&this->state_, 0, &word);
AuAtomicSub(&uValueRef, FAST_M_WAIT);
if (uStatus == NTSTATUS_TIMEOUT)
{
// i suspect we're bailing out too fast
//returnValue = false;
auto uWWaiters = this->state_ & ~FAST_M_WAKE;
if (uWWaiters >= FAST_M_WAIT && _InterlockedCompareExchange(&this->state_, uWWaiters - FAST_M_WAIT, uWWaiters) == uWWaiters)
{
continue;
}
}
else
{
AuAtomicSub(&uValueRef, FAST_M_WAKE);
SysAssertDbg(uStatus == 0);
}
}