/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuMutex.Win32.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuMutex.Generic.hpp" #if !defined(_AURUNTIME_GENERICMUTEX) #include "AuMutex.NT.hpp" namespace Aurora::Threading::Primitives { static BOOL (_stdcall *WaitOnAddress_f)( volatile VOID *Address, PVOID CompareAddress, SIZE_T AddressSize, DWORD dwMilliseconds ) = #if defined(AURORA_PLATFORM_WIN32) decltype(WaitOnAddress_f)(GetProcAddress(LoadLibraryA("API-MS-Win-Core-Synch-l1-2-0.dll"), "WaitOnAddress")); #else WaitOnAddress; #endif static void(_stdcall *WakeByAddressSingle_f)( PVOID Address ) = #if defined(AURORA_PLATFORM_WIN32) decltype(WakeByAddressSingle_f)(GetProcAddress(LoadLibraryA("API-MS-Win-Core-Synch-l1-2-0.dll"), "WakeByAddressSingle")); #else WakeByAddressSingle; #endif Mutex::Mutex() { if (!WaitOnAddress_f) { ::InitializeSRWLock(&this->atomicHolder_); ::InitializeConditionVariable(&this->wakeup_); } this->state_ = 0; } Mutex::~Mutex() { } bool Mutex::HasOSHandle(AuMach &mach) { return false; } bool Mutex::TryLock() { return ::_interlockedbittestandset(&this->state_, 0) == 0; } bool Mutex::HasLockImplementation() { return true; } void Mutex::Lock() { auto status = Lock(0); SysAssert(status, "Couldn't lock Mutex object"); } bool Mutex::Lock(AuUInt64 timeout) { bool returnValue = false; if (this->TryLock()) { return true; } AuInt64 uStartTime = Time::SteadyClockMS(); AuInt64 uEndTime = uStartTime + timeout; if (WaitOnAddress_f) { auto state = this->state_; while (::_interlockedbittestandset(&this->state_, 0) != 0) { AuUInt32 uTimeoutMS = INFINITE; if (timeout != 0) { uStartTime = Time::SteadyClockMS(); if (uStartTime >= uEndTime) { return false; } uTimeoutMS = uEndTime - uStartTime; } if (!WaitOnAddress_f(&this->state_, &state, sizeof(this->state_), uTimeoutMS)) { SysAssertExp(GetLastError() == ERROR_TIMEOUT); return false; } state = this->state_; } return true; } else { ::AcquireSRWLockShared(&this->atomicHolder_); BOOL status = false; while (!this->TryLock()) { AuUInt32 uTimeoutMS = INFINITE; if (timeout != 0) { uStartTime = Time::SteadyClockMS(); if (uStartTime >= uEndTime) { goto exitWin32; } uTimeoutMS = uEndTime - uStartTime; } status = ::SleepConditionVariableSRW(&this->wakeup_, &this->atomicHolder_, uTimeoutMS, CONDITION_VARIABLE_LOCKMODE_SHARED); if (!status) { SysAssertExp(GetLastError() == ERROR_TIMEOUT); goto exitWin32; } } returnValue = true; exitWin32: ::ReleaseSRWLockShared(&this->atomicHolder_); return returnValue; } } void Mutex::Unlock() { if (!WaitOnAddress_f) { ::AcquireSRWLockExclusive(&this->atomicHolder_); this->state_ = 0; ::ReleaseSRWLockExclusive(&this->atomicHolder_); ::WakeAllConditionVariable(&this->wakeup_); } else { this->state_ = 0; WakeByAddressSingle_f((void *)&this->state_); } } AUKN_SYM IWaitable *MutexNew() { return _new Mutex(); } AUKN_SYM void MutexRelease(IWaitable *pMutex) { AuSafeDelete(pMutex); } } #endif