/*** Copyright (C) 2021 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" #if !defined(_AURUNTIME_GENERICCM) namespace Aurora::Threading::Primitives { Win32ConditionMutex::Win32ConditionMutex() { #if !defined(AURORA_FORCE_SRW_LOCKS) if (gKeyedEventHandle == INVALID_HANDLE_VALUE) { if (!pNtCreateKeyedEvent) { InitNTAddresses(); } pNtCreateKeyedEvent(&gKeyedEventHandle, -1, NULL, 0); } #else ::InitializeSRWLock(&this->lock_); #endif } Win32ConditionMutex::~Win32ConditionMutex() { } bool Win32ConditionMutex::TryLock() { #if defined(AURORA_FORCE_SRW_LOCKS) return ::TryAcquireSRWLockExclusive(&this->lock_); #else return DoTryIf([=]() { return !AuAtomicTestAndSet(&this->lock_.uWaitCount, 0); }); #endif } void Win32ConditionMutex::Lock() { #if defined(AURORA_FORCE_SRW_LOCKS) ::AcquireSRWLockExclusive(&this->lock_); #else while (!TryLock()) { auto &uValueRef = this->lock_.uWaitCount; auto uValue = uValueRef | 1; if (AuAtomicCompareExchange(&uValueRef, uValue + kFutexBitWait, uValue) == uValue) { pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); AuAtomicSub(&uValueRef, kFutexBitWake); } } #endif } void Win32ConditionMutex::Unlock() { #if defined(AURORA_FORCE_SRW_LOCKS) ::ReleaseSRWLockExclusive(&this->lock_); #else auto &uValueRef = this->lock_.uWaitCount; AuAtomicAnd(&uValueRef, ~0xFFu); while (true) { auto uOld = uValueRef; auto uValue = uOld; if (uValue & 1) { return; } if (uValue < kFutexBitWait) { return; } if (uValue & kFutexBitWake) { return; } 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 Win32ConditionMutex(); } AUKN_SYM void ConditionMutexRelease(IConditionMutex *pMutex) { AuSafeDelete(pMutex); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ConditionMutex, Win32ConditionMutex) } #endif