/*** Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuConditionMutex.Win32.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuConditionMutex.Generic.hpp" #include "SMTYield.hpp" #include "AuProcAddresses.NT.hpp" #include "../AuWakeInternal.hpp" #if !defined(_AURUNTIME_GENERICCM) namespace Aurora::Threading::Primitives { Win32ConditionMutex::Win32ConditionMutex() { #if !defined(AURORA_FORCE_SRW_LOCKS) #else ::InitializeSRWLock(&this->lock_); #endif } Win32ConditionMutex::~Win32ConditionMutex() { } bool Win32ConditionMutex::TryLock() { #if defined(AURORA_FORCE_SRW_LOCKS) return ::TryAcquireSRWLockExclusive(&this->lock_); #else if (ThrdCfg::gPreferNtCondMutexSpinTryLock) { return this->TryLockHeavy(); } else { return this->TryLockNoSpin(); } #endif } bool Win32ConditionMutex::TryLockHeavy() { return DoTryIfAlderLake([=]() { return this->TryLockNoSpin(); }, &this->lock_); } bool Win32ConditionMutex::TryLockNoSpin() { #if defined(AURORA_FORCE_SRW_LOCKS) return ::TryAcquireSRWLockExclusive(&this->lock_); #else return AuAtomicTestAndSet(&this->lock_.uWaitCount, 0) == 0; #endif } void Win32ConditionMutex::Lock() { #if defined(AURORA_FORCE_SRW_LOCKS) ::AcquireSRWLockExclusive(&this->lock_); #else if (this->TryLockHeavy()) { return; } while (!this->TryLockNoSpin()) { auto &uValueRef = this->lock_.uWaitCount; auto uValue = uValueRef | 1; if (AuAtomicCompareExchange(&uValueRef, uValue + kFutexBitWait, uValue) == uValue) { if (gUseNativeWaitCondvar) { auto uCurrentValue = uValue + kFutexBitWait; InternalLTSWaitOnAddressHighRes((void *)&uValueRef, &uCurrentValue, sizeof(uCurrentValue), 0); } else { pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); AuAtomicSub(&uValueRef, kFutexBitWake); } } } #endif } void Win32ConditionMutex::Unlock() { #if defined(AURORA_FORCE_SRW_LOCKS) ::ReleaseSRWLockExclusive(&this->lock_); #else // Mirrors: ./AuMutex.NT.cpp // keep this codeblock in parity // defer to the comments in that source file auto &uValueRef = this->lock_.uWaitCount; AuAtomicClearU8Lock(&uValueRef); while (true) { auto uOld = uValueRef; auto uValue = uOld; if (uValue & 1) { return; } if (uValue < kFutexBitWait) { return; } if (gUseNativeWaitCondvar) { if (AuAtomicCompareExchange(&uValueRef, uValue - kFutexBitWait, uValue) == uValue) { InternalLTSWakeOne((void *)&uValueRef); return; } } else { if (uValue & kFutexBitWake) { if (AuAtomicCompareExchange(&uValueRef, uValue, uValue) == uValue) { return; } else { SMPPause(); continue; } } if (AuAtomicCompareExchange(&uValueRef, uValue - kFutexBitWait + kFutexBitWake, uValue) == uValue) { pNtReleaseKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); return; } } SMPPause(); } #endif } AuUInt Win32ConditionMutex::GetOSHandle() { return reinterpret_cast(&this->lock_); } AUKN_SYM IConditionMutex *ConditionMutexNew() { return _new ConditionMutexImpl(); } AUKN_SYM void ConditionMutexRelease(IConditionMutex *pMutex) { AuSafeDelete(pMutex); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ConditionMutex, ConditionMutexImpl) } #endif