[*] 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 uEndTimeWall = AuTime::CurrentClockNS() + qwTimeout;
auto uTargetTimeNt = AuTime::ConvertTimestampNs(uEndTimeWall); auto uTargetTimeNt = AuTime::ConvertTimestampNs(uEndTimeWall);
LARGE_INTEGER word; do
word.QuadPart = uTargetTimeNt;
AuAtomicAdd(&this->wlist, 1u);
bRet = pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, &word) != NTSTATUS_TIMEOUT;
if (!bRet)
{ {
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 else
{ {
AuAtomicAdd(&this->wlist, 1u); while (true)
pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, nullptr); {
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 false;
return bRet;
} }
void ConditionVariableImpl::Signal() void ConditionVariableImpl::Signal()
{ {
auto expected = this->wlist; auto original = this->wlist;
AuUInt32 uExpander { this->expander }; 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) 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); pNtReleaseKeyedEvent(gKeyedEventHandle, &this->wlist, FALSE, nullptr);
return;
} }
expected = this->wlist; original = this->wlist;
expected = original >> 2;
} }
} }
} }
void ConditionVariableImpl::Broadcast() void ConditionVariableImpl::Broadcast()
{ {
auto expected = this->wlist; auto original = this->wlist;
AuUInt32 uExpander { this->expander }; 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) 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); 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 Signal() override;
void Broadcast() override; void Broadcast() override;
bool CheckOut(bool &bRet);
private: private:
AuUInt32 wlist {}; AuUInt32 wlist {};
AuUInt32 expander {}; AuUInt32 signalCount {};
AuSPtr<Win32ConditionMutex> mutex_; AuSPtr<Win32ConditionMutex> mutex_;
}; };
} }

View File

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