diff --git a/Source/Threading/Primitives/AuConditionVariable.NT.cpp b/Source/Threading/Primitives/AuConditionVariable.NT.cpp index 7df54343..30412a77 100644 --- a/Source/Threading/Primitives/AuConditionVariable.NT.cpp +++ b/Source/Threading/Primitives/AuConditionVariable.NT.cpp @@ -290,11 +290,30 @@ namespace Aurora::Threading::Primitives if (uSignalNext == 0) { + // Last thread sets the wait-bit (not atomic) InterlockedOr((volatile LONG *)&this->wlist, 1); - if (AuAtomicLoad(&this->signalCount) != 0) [[unlikely]] + AuUInt32 uSignalCount {}; + if ((uSignalCount = AuAtomicLoad(&this->signalCount)) != 0) [[unlikely]] { + // Our CAS was wrong, and we potentially cock-blocked a waking thread, unset the sleep bit + // (note, i dont see this happening in real world applications, but lets continue) + // (also note, this could've been avoided with stict 8-byte atomic ops across all archs. no thank you.) AuAtomicUnset(&this->wlist, 0); + + // WaitOnAddress-based paranoia (only keyed events wont be lost throughout this potential nonatomic race condition): + if (gUseNativeWaitCondvar) + { + // Whatever, NT kernelbase's monitor address signaling is almost free + if (uSignalCount > 1) + { + InternalLTSWakeAll((const void *)&this->wlist); + } + else + { + InternalLTSWakeOne((const void *)&this->wlist); + } + } } }