diff --git a/Source/Threading/AuWakeOnAddress.cpp b/Source/Threading/AuWakeOnAddress.cpp index 739b4c99..e7b00856 100644 --- a/Source/Threading/AuWakeOnAddress.cpp +++ b/Source/Threading/AuWakeOnAddress.cpp @@ -32,7 +32,7 @@ namespace Aurora::Threading static ProcessWaitContainer gProcessWaitables; static int gShouldSpinOnlyInCPU = 1; // TODO: havent decided - + template static void DoSpinLockOnVar(T *uPointer) { @@ -95,7 +95,7 @@ namespace Aurora::Threading AuResetMember(this->uSize); AuResetMember(this->pAddress); } - + WaitEntry::WaitEntry() { @@ -109,7 +109,7 @@ namespace Aurora::Threading bool WaitEntry::SleepOn(WaitState &state) { AU_LOCK_GUARD(this->mutex); - + if (state.qwNanosecondsAbs) { if (!WaitBuffer::Compare(this->pAddress, this->uSize, state)) @@ -132,7 +132,7 @@ namespace Aurora::Threading #if defined(AURORA_PLATFORM_WIN32) Win32DropSchedulerResolution(); #endif - + this->variable.WaitForSignalNsEx(&this->mutex, uTimeRemNS); uNow = AuTime::SteadyClockNS(); @@ -277,8 +277,11 @@ namespace Aurora::Threading Lock(); if (auto pLoadFromMemory = this->waitList.pHead) { - pReturn->pNext = pLoadFromMemory; - pLoadFromMemory->pBefore = pReturn; + if (pLoadFromMemory != pReturn) + { + pReturn->pNext = pLoadFromMemory; + pLoadFromMemory->pBefore = pReturn; + } } else { @@ -313,7 +316,7 @@ namespace Aurora::Threading { pLast->pNext = pCurrentHead->pNext; } - + if (this->waitList.pHead == pCurrentHead) { this->waitList.pHead = pCurrentHead->pNext; @@ -337,6 +340,11 @@ namespace Aurora::Threading } pLast = pCurrentHead; + + if (pCurrentHead->pBefore == pCurrentHead) + { + break; + } pCurrentHead = pCurrentHead->pBefore; } } @@ -345,6 +353,53 @@ namespace Aurora::Threading 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() { DoSpinLockOnVar(&this->uAtomic); @@ -376,6 +431,16 @@ namespace Aurora::Threading 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() { #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) pTempHoldMe.reset(); #endif + + if (!bResult) + { + gProcessWaitables.RemoveSelf(pTargetAddress, pWaitEntry); + } + return bResult; } diff --git a/Source/Threading/AuWakeOnAddress.hpp b/Source/Threading/AuWakeOnAddress.hpp index c089ec25..82de4d64 100644 --- a/Source/Threading/AuWakeOnAddress.hpp +++ b/Source/Threading/AuWakeOnAddress.hpp @@ -87,6 +87,8 @@ namespace Aurora::Threading template bool IterateWake(T callback); + void RemoveSelf(WaitEntry *pSelf); + void Lock(); void Unlock(); @@ -100,5 +102,7 @@ namespace Aurora::Threading template bool IterateWake(const void *pAddress, T callback); + + void RemoveSelf(const void *pAddress, WaitEntry *pSelf); }; } \ No newline at end of file