/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuMutex.NT.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuMutex.Generic.hpp" #include "SMPYield.hpp" #if !defined(_AURUNTIME_GENERICMUTEX) #include "AuMutex.NT.hpp" namespace Aurora::Threading::Primitives { Mutex::Mutex() { if (!pWaitOnAddress) { ::InitializeSRWLock(&this->atomicHolder_); ::InitializeConditionVariable(&this->wakeup_); } this->state_ = 0; } Mutex::~Mutex() { } bool Mutex::HasOSHandle(AuMach &mach) { return false; } bool Mutex::TryLock() { return DoTryIf([=]() { 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 uTimeout) { return LockNS(AuMSToNS(uTimeout)); } bool Mutex::LockNS(AuUInt64 uTimeout) { bool returnValue = false; if (this->TryLock()) { return true; } AuUInt64 uStartTime = Time::SteadyClockNS(); AuUInt64 uEndTime = uStartTime + uTimeout; if (pWaitOnAddress) { auto state = this->state_; while (::_interlockedbittestandset(&this->state_, 0) != 0) { AuUInt32 uTimeoutMS = INFINITE; if (uTimeout != 0) { uStartTime = Time::SteadyClockNS(); if (uStartTime >= uEndTime) { return false; } uTimeoutMS = AuNSToMS(uEndTime - uStartTime); } if (!uTimeoutMS) { SMPPause(); AuThreading::ContextYield(); } else { (void)pWaitOnAddress(&this->state_, &state, sizeof(this->state_), uTimeoutMS); } state = this->state_; } return true; } else { ::AcquireSRWLockShared(&this->atomicHolder_); BOOL status = false; while (!this->TryLock()) { AuUInt32 uTimeoutMS = INFINITE; if (uTimeout != 0) { uStartTime = Time::SteadyClockNS(); if (uStartTime >= uEndTime) { goto exitWin32; } uTimeoutMS = AuNSToMS(uEndTime - uStartTime); } if (!uTimeoutMS) { ::ReleaseSRWLockShared(&this->atomicHolder_); SMPPause(); AuThreading::ContextYield(); ::AcquireSRWLockShared(&this->atomicHolder_); } else { (void)SleepConditionVariableSRW(&this->wakeup_, &this->atomicHolder_, uTimeoutMS, CONDITION_VARIABLE_LOCKMODE_SHARED); } } returnValue = true; exitWin32: ::ReleaseSRWLockShared(&this->atomicHolder_); return returnValue; } } void Mutex::Unlock() { if (!pWaitOnAddress) { ::AcquireSRWLockExclusive(&this->atomicHolder_); this->state_ = 0; ::ReleaseSRWLockExclusive(&this->atomicHolder_); ::WakeAllConditionVariable(&this->wakeup_); } else { this->state_ = 0; pWakeByAddressSingle((void *)&this->state_); } } AUKN_SYM IWaitable *MutexNew() { return _new Mutex(); } AUKN_SYM void MutexRelease(IWaitable *pMutex) { AuSafeDelete(pMutex); } } #endif