[*] 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 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user