/*** Copyright (C) 2021-2024 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuConditionMutex.Generic.cpp Date: 2021-6-14 Author: Reece ***/ #include #include "AuConditionMutex.Generic.hpp" #include "../AuWakeInternal.hpp" #include "SMTYield.hpp" #if defined(_AURUNTIME_GENERICCM) namespace Aurora::Threading::Primitives { GenericConditionMutex::GenericConditionMutex() { } GenericConditionMutex::~GenericConditionMutex() { } bool GenericConditionMutex::TryLock() { if (ThrdCfg::gPreferLinuxCondMutexSpinTryLock) { return this->TryLockHeavy(); } else { return this->TryLockNoSpin(); } } void GenericConditionMutex::Lock() { if (ThrdCfg::gPreferUnixPrimitivesNoSpin) { if (this->TryLockNoSpin()) { return; } } else { if (this->TryLockHeavy()) { return; } } AuAtomicAdd(&this->uSleeping_, 1u); while (!this->TryLockNoSpin()) { static const AuUInt32 kRef { 1 }; (void)InternalLTSWaitOnAddressHighRes(&this->uState_, &kRef, 4, 0); } AuAtomicSub(&this->uSleeping_, 1u); } void GenericConditionMutex::Unlock() { AuAtomicClearU8Lock(&this->uState_); if (AuAtomicLoad(&this->uSleeping_)) { InternalLTSWakeOne(&this->uState_); } } bool GenericConditionMutex::TryLockNoSpin() { return AuAtomicTestAndSet(&this->uState_, 0) == 0; } bool GenericConditionMutex::TryLockHeavy() { return DoTryIfAlderLake([=]() { return this->TryLockNoSpin(); }, &this->uState_); } bool GenericConditionMutex::LockAbsNS(AuUInt64 uEndTime) { bool bStatus { true }; if (this->TryLock()) { return true; } AuAtomicAdd(&this->uSleeping_, 1u); while (!this->TryLockNoSpin()) { static const AuUInt32 kRef { 1 }; if (uEndTime != 0) { if (!InternalLTSWaitOnAddressHighRes(&this->uState_, &kRef, 4, uEndTime)) { bStatus = false; break; } } else { (void)InternalLTSWaitOnAddressHighRes(&this->uState_, &kRef, 4, uEndTime); } } AuAtomicSub(&this->uSleeping_, 1u); return bStatus; } bool GenericConditionMutex::LockNS(AuUInt64 uTimeout) { AuUInt64 uEndTime {}; bool bStatus { true }; if (this->TryLock()) { return true; } if (uTimeout != 0) { uEndTime = AuTime::SteadyClockNS() + uTimeout; } if (!ThrdCfg::gPreferUnixPrimitivesNoSpin) { if (this->TryLockHeavy()) { return true; } } AuAtomicAdd(&this->uSleeping_, 1u); while (!this->TryLockNoSpin()) { static const AuUInt32 kRef { 1 }; if (uTimeout != 0) { if (!InternalLTSWaitOnAddressHighRes(&this->uState_, &kRef, 4, uEndTime)) { bStatus = false; break; } } else { (void)InternalLTSWaitOnAddressHighRes(&this->uState_, &kRef, 4, uEndTime); } } AuAtomicSub(&this->uSleeping_, 1u); return bStatus; } bool GenericConditionMutex::LockAbsMS(AuUInt64 timeout) { return this->LockAbsNS(AuMSToNS(timeout)); } bool GenericConditionMutex::LockMS(AuUInt64 timeout) { return this->LockNS(AuMSToNS(timeout)); } AuUInt GenericConditionMutex::GetOSHandle() { return 0; } AUKN_SYM IConditionMutex *ConditionMutexNew() { return _new ConditionMutexGenericImpl(); } AUKN_SYM void ConditionMutexRelease(IConditionMutex *pMutex) { AuSafeDelete(pMutex); } AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, ConditionMutex, ConditionMutexGenericImpl) } #endif