/*** Copyright (C) 2023 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: LSLocalMutex.cpp Date: 2023-10-21 Author: Reece ***/ #include #include "LSLocalMutex.hpp" #include namespace Aurora::IO::Loop { static auto const kFutexBitWake = 256u; extern AuRWRenterableLock gWaitForMultipleALLLock; LSLocalMutex::LSLocalMutex() { } LSLocalMutex::~LSLocalMutex() { } bool LSLocalMutex::TryInit() { if (!LSSemaphore::TryInit(1)) { return false; } return true; } bool LSLocalMutex::OnTrigger(AuUInt handle) { if (AuAtomicLoad(&this->uAtomicWord) & kFutexBitWake) { (void)LSSemaphore::OnTrigger(0); AuAtomicSub(&this->uAtomicWord, kFutexBitWake); } return this->TryTakeNoSpin(); } bool LSLocalMutex::Unlock() { if (!(AuAtomicLoad(&this->uAtomicWord) & 1)) { return false; } AuAtomicClearU8Lock(&this->uAtomicWord); while (true) { auto uState = AuAtomicLoad(&this->uAtomicWord); if (uState & 1) { return true; } if (uState & kFutexBitWake) { if (AuAtomicCompareExchange(&this->uAtomicWord, uState, uState) == uState) { return true; } else { continue; } } if (AuAtomicCompareExchange(&this->uAtomicWord, uState + kFutexBitWake, uState) == uState) { LSSemaphore::AddOne(); return true; } } } bool LSLocalMutex::IsSignaled() { return this->TryTake(); } bool LSLocalMutex::IsSignaledNoSpinIfUserland() { return this->TryTakeNoSpin(); } ELoopSource LSLocalMutex::GetType() { return ELoopSource::eSourceFastMutex; } bool LSLocalMutex::TryTakeNoSpin() { return AuAtomicTestAndSet(&this->uAtomicWord, 0) == 0; } bool LSLocalMutex::TryTakeSpin() { bool bRet = Threading::Primitives::DoTryIfAlderLake([&] { return this->TryTakeNoSpin(); }, &this->uAtomicWord); #if !defined(AU_NO_WAITMULTIPLELS_ALL_MS_PARITY) if (!bRet && gRuntimeConfig.ioConfig.bAimCloserForNTParityWaitALL) { AU_LOCK_GLOBAL_GUARD(gWaitForMultipleALLLock->AsReadable()); bRet = this->TryTakeNoSpin(); } #endif return bRet; } bool LSLocalMutex::TryTake() { return this->TryTakeSpin(); } bool LSLocalMutex::TryTakeWaitNS(AuUInt64 uEndTime) { if (this->TryTakeSpin()) { return true; } while (!this->TryTakeNoSpin()) { if (!uEndTime) { if (LSSemaphore::WaitOn(0)) { return true; } } else { auto uStartTime = Time::SteadyClockNS(); if (uStartTime >= uEndTime) { return false; } auto uDeltaMs = AuNSToMS(uEndTime - uStartTime); if (uDeltaMs && LSSemaphore::WaitOn(uDeltaMs)) { return true; } else if (!uDeltaMs) { if (this->TryTakeSpin()) { return true; } } } } return true; } AUKN_SYM AuSPtr NewLSMutex() { #if defined(AURORA_IS_MODERNNT_DERIVED) if (gRuntimeConfig.ioConfig.bINeedPerfectAnds) { return NewLSMutexSlow(); } #endif auto pMutex = AuMakeShared(); if (!pMutex) { SysPushErrorGeneric(); return {}; } if (!pMutex->TryInit()) { SysPushErrorNested(); return {}; } return pMutex; } }