/*** 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 "SMPYield.hpp" #include "AuProcAddresses.NT.hpp" #if !defined(_AURUNTIME_GENERICCM) namespace Aurora::Threading::Primitives { Win32ConditionMutex::Win32ConditionMutex() { if (gKeyedEventHandle == INVALID_HANDLE_VALUE) { if (!pNtCreateKeyedEvent) { InitNTAddresses(); } pNtCreateKeyedEvent(&gKeyedEventHandle, -1, NULL, 0); } } Win32ConditionMutex::~Win32ConditionMutex() { } bool Win32ConditionMutex::TryLock() { return DoTryIf([=]() { return !AuAtomicTestAndSet(&this->lock_.uWaitCount, 0); }); } void Win32ConditionMutex::Lock() { while (!TryLock()) { auto &uValueRef = this->lock_.uWaitCount; auto uValue = uValueRef | 1; if (AuAtomicCompareExchange(&uValueRef, uValue + FAST_M_WAIT, uValue) == uValue) { pNtWaitForKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); AuAtomicSub(&uValueRef, FAST_M_WAKE); } } } void Win32ConditionMutex::Unlock() { auto &uValueRef = this->lock_.uWaitCount; while (true) { auto uNow = uValueRef; auto uNext = uNow & ~0xFF; if (AuAtomicCompareExchange(&uValueRef, uNext, uNow) == uNow) { break; } } while (true) { auto uOld = uValueRef; auto uValue = uOld; if (uValue & 1) { return; } if (uValue < FAST_M_WAIT) { return; } if (uValue & FAST_M_WAKE) { return; } if (AuAtomicCompareExchange(&uValueRef, uValue - FAST_M_WAIT + FAST_M_WAKE, uValue) == uValue) { pNtReleaseKeyedEvent(gKeyedEventHandle, (void *)&uValueRef, 0, NULL); return; } SMPPause(); } } AuUInt Win32ConditionMutex::GetOSHandle() { return reinterpret_cast(&this->lock_); } AUKN_SYM IConditionMutex *ConditionMutexNew() { return _new Win32ConditionMutex(); } AUKN_SYM void ConditionMutexRelease(IConditionMutex *pMutex) { AuSafeDelete(pMutex); } } #endif