From 2b0ed79729d0fa7e9272a7d85e27f39605086dda Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Thu, 8 Feb 2024 03:54:48 +0000 Subject: [PATCH] [*] NT Condvar hardening: Windows XP-7 hardening of the spin condition when racing against multiple threads --- .../Primitives/AuConditionVariable.NT.cpp | 45 +++++++++++++++++++ .../Primitives/AuConditionVariable.NT.hpp | 1 + 2 files changed, 46 insertions(+) diff --git a/Source/Threading/Primitives/AuConditionVariable.NT.cpp b/Source/Threading/Primitives/AuConditionVariable.NT.cpp index 2479dd21..a890823f 100644 --- a/Source/Threading/Primitives/AuConditionVariable.NT.cpp +++ b/Source/Threading/Primitives/AuConditionVariable.NT.cpp @@ -158,6 +158,11 @@ namespace Aurora::Threading::Primitives return true; } + if (!gUseNativeWaitCondvar) + { + this->SignalSpuriously(); + } + this->AddWaiter(); } } @@ -213,6 +218,11 @@ namespace Aurora::Threading::Primitives return bRet; } + if (!gUseNativeWaitCondvar) + { + this->SignalSpuriously(); + } + this->AddWaiter(); } } @@ -324,6 +334,41 @@ namespace Aurora::Threading::Primitives }); #endif } + + void ConditionVariableNT::SignalSpuriously() + { + #if !defined(AURORA_FORCE_SRW_LOCKS) + auto original = this->wlist; + auto expected = original; + expected = expected >> kShiftCountByBits; + + if (expected) + { + // NOTE: missing this->signalCount atomic increment to force another AddWaiter under successful keyedevent return + while (expected) + { + if (AuAtomicCompareExchange(&this->wlist, ((expected - 1) << kShiftCountByBits) /*intentional clear*/, original) == original) + { + if (gUseNativeWaitCondvar) + { + InternalLTSWakeOne((void *)&this->wlist); + } + else + { + pNtReleaseKeyedEvent(gKeyedEventHandle, (void *)&this->wlist, FALSE, nullptr); + } + + return; + } + + original = this->wlist; + expected = original >> kShiftCountByBits; + } + } + #else + ::WakeConditionVariable(&this->winCond_); + #endif + } void ConditionVariableNT::Signal() { diff --git a/Source/Threading/Primitives/AuConditionVariable.NT.hpp b/Source/Threading/Primitives/AuConditionVariable.NT.hpp index ae9c38ff..ecaa123b 100644 --- a/Source/Threading/Primitives/AuConditionVariable.NT.hpp +++ b/Source/Threading/Primitives/AuConditionVariable.NT.hpp @@ -19,6 +19,7 @@ namespace Aurora::Threading::Primitives bool WaitForSignalNsEx(Win32ConditionMutex *pMutex, AuUInt64 timeout, bool bSpin = true); void Signal(); + auline void SignalSpuriously(); void Broadcast(); void BroadcastN(AuUInt32 nBroadcast);