[*] Further work on the legacy NT primitives

(can still be improved, optimized, and bug fixed)
(will add a build toggle between the old SRW and this)
(...and ironically it seems like our time to wake times are worse now)
This commit is contained in:
Reece Wilson 2023-03-15 16:06:58 +00:00
parent 0ad854284e
commit 89057139b3
4 changed files with 83 additions and 72 deletions

View File

@ -46,11 +46,11 @@ namespace Aurora::Threading::Primitives
{
auto &uValueRef = this->lock_.uWaitCount;
auto uValue = uValueRef | 1;
if (AuAtomicCompareExchange(&uValueRef, uValue + FAST_M_WAIT, uValue) == uValue)
{
pNtWaitForKeyedEvent(gKeyedEventHandle, &uValueRef, 0, NULL);
pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL);
AuAtomicSub(&uValueRef, FAST_M_WAKE);
}
}
@ -59,39 +59,44 @@ namespace Aurora::Threading::Primitives
void Win32ConditionMutex::Unlock()
{
auto &uValueRef = this->lock_.uWaitCount;
auto uValue = uValueRef;
if (uValue == 1)
while (true)
{
if (AuAtomicCompareExchange(&uValueRef, 0u, 1u) == 1u)
auto uNow = uValueRef;
auto uNext = uNow & ~0xFF;
if (AuAtomicCompareExchange(&uValueRef, uNext, uNow) == uNow)
{
return;
break;
}
}
while (true)
{
if (uValue < FAST_M_WAIT)
{
return;
}
auto uOld = uValueRef;
auto uValue = uOld;
if (uValue & 1)
{
return;
}
if (uValue < FAST_M_WAIT)
{
return;
}
if (uValue & FAST_M_WAKE)
{
return;
}
if (AuAtomicCompareExchange(&uValueRef, uValue - FAST_M_WAIT + FAST_M_WAKE, uValue) == uValue)
{
pNtReleaseKeyedEvent(gKeyedEventHandle, &uValueRef, 0, NULL);
pNtReleaseKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL);
return;
}
SMPPause();
}
}

View File

@ -19,7 +19,7 @@ namespace Aurora::Threading::Primitives
struct NT4Mutex
{
AuUInt32 uWaitCount {}; // yields while bits are high, dec to release one from the semaphore yield
volatile AuUInt32 uWaitCount {}; // yields while bits are high, dec to release one from the semaphore yield
};
struct Win32ConditionMutex : IConditionMutexEx

View File

@ -50,7 +50,7 @@ namespace Aurora::Threading::Primitives
{
LARGE_INTEGER word;
word.QuadPart = uTargetTimeNt;
if (bRet)
{
while (true)
@ -76,17 +76,43 @@ namespace Aurora::Threading::Primitives
if (!bRet && uEndTimeSteady <= AuTime::SteadyClockNS())
{
while (true)
{
auto uNow = this->wlist;
auto waiting = (uNow >> 2u) - 1u;
auto uNext = waiting << 2u;
auto uNow = this->wlist;
auto uOld = (uNow >> 2u);
if (AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow)
if (uOld == 0)
{
// broadcast has woken everyone up
if (CheckOut(bRet)) // the cope acquire
{
// in which case we're good
this->mutex_->Lock();
return false;
return true;
}
else
{
// in which case we're still dealaing with out overflowed waitlist
bRet = false;
continue;
}
}
// go for atomic decrement
auto waiting = uOld - 1u;
auto uNext = waiting << 2u;
if (AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow)
{
// break if successful
this->mutex_->Lock();
return false;
}
else
{
// block again because we couldn't decrement the counter
// broadcast still thinks we're asleep
// ...and we still owe NtReleaseKeyedEvent 1 therad
continue;
}
}
else
@ -119,50 +145,28 @@ namespace Aurora::Threading::Primitives
pNtWaitForKeyedEvent(gKeyedEventHandle, &this->wlist, 0, nullptr);
if (!CheckOut(bRet))
if (CheckOut(bRet))
{
continue;
this->mutex_->Lock();
return bRet;
}
}
this->mutex_->Lock();
return bRet;
}
}
bool ConditionVariableImpl::CheckOut(bool &bRet)
{
auto uSignalNow = this->signalCount;
if (uSignalNow == 0)
{
return false;
}
while (!DoTryIf([=]()
return DoTryIf([&]()
{
auto uSignalNow = this->signalCount;
return AuAtomicCompareExchange(&this->signalCount, uSignalNow - 1, uSignalNow) == uSignalNow;
}))
{
auto uSignalValue = this->signalCount - 1;
while (!DoTryIf([=]()
if (uSignalNow == 0)
{
auto uNow = this->wlist;
auto waiting = (uNow >> 2u);
auto uNext = waiting << 2u;
return false;
}
if (!uSignalValue)
{
uNext |= 1; // block after flush complete
}
return AuAtomicCompareExchange(&this->wlist, uNext, uNow) == uNow;
}));
}
return true;
return AuAtomicCompareExchange(&this->signalCount, uSignalNow - 1, uSignalNow) == uSignalNow;
});
}
void ConditionVariableImpl::Signal()
@ -173,12 +177,11 @@ namespace Aurora::Threading::Primitives
if (expected)
{
AuAtomicAdd(&this->signalCount, 1u);
while (expected)
{
expected--;
AuAtomicAdd(&this->signalCount, 1u);
if (AuAtomicCompareExchange(&this->wlist, (expected << 2) /*intentional clear*/, original) == original)
if (AuAtomicCompareExchange(&this->wlist, ((expected - 1) << 2) /*intentional clear*/, original) == original)
{
pNtReleaseKeyedEvent(gKeyedEventHandle, &this->wlist, FALSE, nullptr);
return;
@ -196,21 +199,21 @@ namespace Aurora::Threading::Primitives
auto expected = original;
expected = expected >> 2;
while (expected)
auto uBroadcastIterations = expected;
while (expected && uBroadcastIterations)
{
while (expected)
if (AuAtomicCompareExchange(&this->wlist, ((expected - 1) << 2) /*intentional clear*/, original) == original)
{
expected--;
AuAtomicAdd(&this->signalCount, 1u);
if (AuAtomicCompareExchange(&this->wlist, (expected << 2) /*intentional clear*/, original) == original)
{
pNtReleaseKeyedEvent(gKeyedEventHandle, &this->wlist, FALSE, nullptr);
}
original = this->wlist;
expected = original >> 2;
pNtReleaseKeyedEvent(gKeyedEventHandle, &this->wlist, FALSE, nullptr);
uBroadcastIterations--;
}
original = this->wlist;
expected = original >> 2;
}
}

View File

@ -229,11 +229,14 @@ namespace Aurora::Threading::Primitives
auto &uValueRef = this->state_;
auto uValue = uValueRef;
if (uValue == 1)
while (true)
{
if (AuAtomicCompareExchange(&uValueRef, 0u, 1u) == 1u)
auto uNow = uValueRef;
auto uNext = uNow & ~0xFF;
if (AuAtomicCompareExchange(&uValueRef, uNext, uNow) == uNow)
{
return;
break;
}
}