[*] Resolve WakeOnAddress emu-mode bug and a potential dead-lock

This commit is contained in:
Reece Wilson 2023-11-17 23:06:08 +00:00
parent b88c61c16d
commit 63b72a9fb5
2 changed files with 82 additions and 7 deletions

View File

@ -32,7 +32,7 @@ namespace Aurora::Threading
static ProcessWaitContainer gProcessWaitables; static ProcessWaitContainer gProcessWaitables;
static int gShouldSpinOnlyInCPU = 1; // TODO: havent decided static int gShouldSpinOnlyInCPU = 1; // TODO: havent decided
template<typename T> template<typename T>
static void DoSpinLockOnVar(T *uPointer) static void DoSpinLockOnVar(T *uPointer)
{ {
@ -95,7 +95,7 @@ namespace Aurora::Threading
AuResetMember(this->uSize); AuResetMember(this->uSize);
AuResetMember(this->pAddress); AuResetMember(this->pAddress);
} }
WaitEntry::WaitEntry() WaitEntry::WaitEntry()
{ {
@ -109,7 +109,7 @@ namespace Aurora::Threading
bool WaitEntry::SleepOn(WaitState &state) bool WaitEntry::SleepOn(WaitState &state)
{ {
AU_LOCK_GUARD(this->mutex); AU_LOCK_GUARD(this->mutex);
if (state.qwNanosecondsAbs) if (state.qwNanosecondsAbs)
{ {
if (!WaitBuffer::Compare(this->pAddress, this->uSize, state)) if (!WaitBuffer::Compare(this->pAddress, this->uSize, state))
@ -132,7 +132,7 @@ namespace Aurora::Threading
#if defined(AURORA_PLATFORM_WIN32) #if defined(AURORA_PLATFORM_WIN32)
Win32DropSchedulerResolution(); Win32DropSchedulerResolution();
#endif #endif
this->variable.WaitForSignalNsEx(&this->mutex, uTimeRemNS); this->variable.WaitForSignalNsEx(&this->mutex, uTimeRemNS);
uNow = AuTime::SteadyClockNS(); uNow = AuTime::SteadyClockNS();
@ -277,8 +277,11 @@ namespace Aurora::Threading
Lock(); Lock();
if (auto pLoadFromMemory = this->waitList.pHead) if (auto pLoadFromMemory = this->waitList.pHead)
{ {
pReturn->pNext = pLoadFromMemory; if (pLoadFromMemory != pReturn)
pLoadFromMemory->pBefore = pReturn; {
pReturn->pNext = pLoadFromMemory;
pLoadFromMemory->pBefore = pReturn;
}
} }
else else
{ {
@ -313,7 +316,7 @@ namespace Aurora::Threading
{ {
pLast->pNext = pCurrentHead->pNext; pLast->pNext = pCurrentHead->pNext;
} }
if (this->waitList.pHead == pCurrentHead) if (this->waitList.pHead == pCurrentHead)
{ {
this->waitList.pHead = pCurrentHead->pNext; this->waitList.pHead = pCurrentHead->pNext;
@ -337,6 +340,11 @@ namespace Aurora::Threading
} }
pLast = pCurrentHead; pLast = pCurrentHead;
if (pCurrentHead->pBefore == pCurrentHead)
{
break;
}
pCurrentHead = pCurrentHead->pBefore; pCurrentHead = pCurrentHead->pBefore;
} }
} }
@ -345,6 +353,53 @@ namespace Aurora::Threading
return bRetStatus; return bRetStatus;
} }
void ProcessWaitNodeContainer::RemoveSelf(WaitEntry *pSelf)
{
Lock();
{
auto pCurrentHead = this->waitList.pTail;
decltype(pCurrentHead) pLast {};
while (pCurrentHead)
{
if (pCurrentHead == pSelf)
{
if (pLast)
{
pLast->pNext = pCurrentHead->pNext;
}
if (this->waitList.pHead == pCurrentHead)
{
this->waitList.pHead = pCurrentHead->pNext;
}
if (pCurrentHead->pNext)
{
pCurrentHead->pNext->pBefore = pCurrentHead->pBefore;
}
if (this->waitList.pTail == pCurrentHead)
{
this->waitList.pTail = pCurrentHead->pBefore;
}
break;
}
pLast = pCurrentHead;
if (pCurrentHead->pBefore == pCurrentHead)
{
break;
}
pCurrentHead = pCurrentHead->pBefore;
}
}
Unlock();
}
void ProcessWaitNodeContainer::Lock() void ProcessWaitNodeContainer::Lock()
{ {
DoSpinLockOnVar(&this->uAtomic); DoSpinLockOnVar(&this->uAtomic);
@ -376,6 +431,16 @@ namespace Aurora::Threading
return this->list[AuHashCode(pAddressIDC) % AuArraySize(this->list)].IterateWake(callback); return this->list[AuHashCode(pAddressIDC) % AuArraySize(this->list)].IterateWake(callback);
} }
void ProcessWaitContainer::RemoveSelf(const void *pAddress, WaitEntry *pSelf)
{
#if defined(FALLBACK_WAKEONADDRESS_SUPPORTS_NONEXACT_MATCHING)
auto pAddressIDC = (void *)(AuUInt(pAddress) & ~(8 - 1));
#else
auto pAddressIDC = pAddress;
#endif
return this->list[AuHashCode(pAddressIDC) % AuArraySize(this->list)].RemoveSelf(pSelf);
}
bool IsNativeWaitOnSupported() bool IsNativeWaitOnSupported()
{ {
#if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_IS_MODERNNT_DERIVED)
@ -450,6 +515,12 @@ namespace Aurora::Threading
#if defined(HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD) #if defined(HACK_NO_INVALID_ACCESS_LEAK_SHARED_REF_ON_DESTROYED_THREAD)
pTempHoldMe.reset(); pTempHoldMe.reset();
#endif #endif
if (!bResult)
{
gProcessWaitables.RemoveSelf(pTargetAddress, pWaitEntry);
}
return bResult; return bResult;
} }

View File

@ -87,6 +87,8 @@ namespace Aurora::Threading
template <typename T> template <typename T>
bool IterateWake(T callback); bool IterateWake(T callback);
void RemoveSelf(WaitEntry *pSelf);
void Lock(); void Lock();
void Unlock(); void Unlock();
@ -100,5 +102,7 @@ namespace Aurora::Threading
template <typename T> template <typename T>
bool IterateWake(const void *pAddress, T callback); bool IterateWake(const void *pAddress, T callback);
void RemoveSelf(const void *pAddress, WaitEntry *pSelf);
}; };
} }