[*] 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:
parent
0ad854284e
commit
89057139b3
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user