/*** Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Mutex.Generic.cpp Date: 2021-6-12 Author: Reece ***/ #include #include "AuMutex.Generic.hpp" #include "../AuWakeInternal.hpp" #include "SMTYield.hpp" #if defined(_AURUNTIME_GENERIC_MUTEX) namespace Aurora::Threading::Primitives { MutexGenericImpl::MutexGenericImpl() { this->state_ = 0; } MutexGenericImpl::~MutexGenericImpl() { } bool MutexGenericImpl::HasOSHandle(AuMach &mach) { return false; } bool MutexGenericImpl::HasLockImplementation() { return true; } bool MutexGenericImpl::TryLock() { if (ThrdCfg::gPreferUnixPrimitivesNoSpin) { return this->TryLockNoSpin(); } else { return this->TryLockHeavy(); } } bool MutexGenericImpl::TryLockNoSpin() { return AuAtomicTestAndSet(&this->state_, 0) == 0; } bool MutexGenericImpl::TryLockHeavy() { return DoTryIfAlderLake([=]() { return this->TryLockNoSpin(); }, &this->state_); } bool MutexGenericImpl::LockMS(AuUInt64 uTimeout) { return this->LockNS(AuMSToNS(uTimeout)); } bool MutexGenericImpl::LockNS(AuUInt64 uTimeout) { AuUInt64 uStart {}; AuUInt64 uEnd {}; bool bStatus { true }; if (this->TryLockNoSpin()) { return true; } if (uTimeout != 0) { uStart = AuTime::SteadyClockNS(); uEnd = uStart + uTimeout; } if (this->TryLock()) { return true; } AuAtomicAdd(&this->dwSleeping_, 1u); while (!this->TryLockNoSpin()) { static const AuUInt32 kRef { 1 }; if (uTimeout != 0) { if (!InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEnd)) { bStatus = false; break; } } else { (void)InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEnd); } } AuAtomicSub(&this->dwSleeping_, 1u); return bStatus; } bool MutexGenericImpl::LockAbsNS(AuUInt64 uEndTime) { bool bStatus { true }; if (ThrdCfg::gPreferUnixPrimitivesNoSpin) { if (this->TryLockNoSpin()) { return true; } } else { if (this->TryLockHeavy()) { return true; } } AuAtomicAdd(&this->dwSleeping_, 1u); while (!this->TryLockNoSpin()) { static const AuUInt32 kRef { 1 }; if (uEndTime != 0) { if (!InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEndTime)) { bStatus = false; break; } } else { (void)InternalLTSWaitOnAddressHighRes((void *)&this->state_, &kRef, 4, uEndTime); } } AuAtomicSub(&this->dwSleeping_, 1u); return bStatus; } void MutexGenericImpl::SlowLock() { (void)this->LockAbsNS(0); } void MutexGenericImpl::Unlock() { AuAtomicClearU8Lock(&this->state_); if (AuAtomicLoad(&this->dwSleeping_)) { InternalLTSWakeOne((void *)&this->state_); } } AUKN_SYM IHyperWaitable *MutexNew() { return _new MutexGenericImpl(); } AUKN_SYM void MutexRelease(IHyperWaitable *pMutex) { AuSafeDelete(pMutex); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, Mutex, MutexGenericImpl) } #endif