[*] i need sleep and i broke the core primitives
This commit is contained in:
parent
f354a202ad
commit
49bfecee32
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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_;
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user