diff --git a/Source/Threading/Primitives/AuEvent.cpp b/Source/Threading/Primitives/AuEvent.cpp index 10960423..9b4b2576 100644 --- a/Source/Threading/Primitives/AuEvent.cpp +++ b/Source/Threading/Primitives/AuEvent.cpp @@ -48,6 +48,8 @@ namespace Aurora::Threading::Primitives if (gPreferFutexEvent) { + auto pSleepCounter = GetSleepCounter(); + while (!AtomicIsEventSetLogicNoSpinNoLock()) { EventBits bits; @@ -55,7 +57,11 @@ namespace Aurora::Threading::Primitives if (bits.bTriggered) { - if (!InternalLTSWaitOnAddressHighRes(&this->state_, &bits.state, sizeof(bits.state), uEndTime)) + AuAtomicAdd(pSleepCounter, 1u); + bool bStatus = InternalLTSWaitOnAddressHighRes(&this->state_, &bits.state, sizeof(bits.state), uEndTime); + AuAtomicSub(pSleepCounter, 1u); + + if (!bStatus) { return false; } @@ -94,6 +100,68 @@ namespace Aurora::Threading::Primitives return true; } + + bool EventImpl::LockAbsNS(AuUInt64 uEndTime) + { + if (AtomicIsEventSetLogicNoSpinNoLock()) + { + return true; + } + + if (gPreferFutexEvent) + { + auto pSleepCounter = GetSleepCounter(); + + while (!AtomicIsEventSetLogicNoSpinNoLock()) + { + EventBits bits; + bits.state = AuAtomicLoad(&this->state_); + + if (bits.bTriggered) + { + AuAtomicAdd(pSleepCounter, 1u); + bool bStatus = InternalLTSWaitOnAddressHighRes(&this->state_, &bits.state, sizeof(bits.state), uEndTime); + AuAtomicSub(pSleepCounter, 1u); + + if (!bStatus) + { + return false; + } + } + else + { + SMPPause(); + } + } + } + else + { + AU_LOCK_GUARD(this->mutex_); + + while (!AtomicIsEventSetLogicNoSpinNoLock()) + { + AuUInt32 uTimeoutNS {}; + + if (uEndTime) + { + auto uStartTime = Time::SteadyClockNS(); + if (uStartTime >= uEndTime) + { + return false; + } + + uTimeoutNS = uEndTime - uStartTime; + } + + if (!this->condition_.WaitForSignalNsEx(&this->mutex_, uTimeoutNS)) + { + continue; + } + } + } + + return true; + } bool EventImpl::TryLock() { @@ -199,6 +267,11 @@ namespace Aurora::Threading::Primitives { if (gPreferFutexEvent) { + if (!AuAtomicLoad(GetSleepCounter())) + { + return; + } + if (bits.bAtomicRelease) { InternalLTSWakeOne(&this->state_); @@ -246,6 +319,11 @@ namespace Aurora::Threading::Primitives // Unlock is always a NOP; inverse of a lock/wait is nothing } + AuUInt32 *EventImpl::GetSleepCounter() + { + return (AuUInt32 *)&this->condition_; + } + AUKN_SYM IEvent *EventNew(bool bTriggered, bool bAtomicRelease, bool bPermitMultipleTriggers) { auto event = _new EventImpl(bTriggered, bAtomicRelease, bPermitMultipleTriggers); diff --git a/Source/Threading/Primitives/AuEvent.hpp b/Source/Threading/Primitives/AuEvent.hpp index b3424fbf..4ee3a9ce 100644 --- a/Source/Threading/Primitives/AuEvent.hpp +++ b/Source/Threading/Primitives/AuEvent.hpp @@ -20,6 +20,7 @@ namespace Aurora::Threading::Primitives bool Init(); bool LockMS(AuUInt64 timeout /*=0*/) override; bool LockNS(AuUInt64 timeout /*=0*/) override; + bool LockAbsNS(AuUInt64 timeout /*=0*/) override; bool TryLock() override; void Reset() override; void Set() override; @@ -28,7 +29,8 @@ namespace Aurora::Threading::Primitives bool HasLockImplementation() override; void Lock() override; void Unlock() override; - + auline AuUInt32 *GetSleepCounter(); + private: bool AtomicIsEventSetLogicNoSpinNoLock(); diff --git a/Source/Threading/Primitives/SMTYield.cpp b/Source/Threading/Primitives/SMTYield.cpp index 32ee3adc..63c3e559 100644 --- a/Source/Threading/Primitives/SMTYield.cpp +++ b/Source/Threading/Primitives/SMTYield.cpp @@ -62,6 +62,7 @@ namespace Aurora::Threading ThreadingConfig cpy(*pUpdateConfig); cpy.bPreferFutexRWLock = Primitives::ThrdCfg::gPreferFutexRWLock; + cpy.bPreferFutexEvent = Primitives::ThrdCfg::gPreferFutexEvent; cpy.bPreferEmulatedWakeOnAddress = Primitives::ThrdCfg::gPreferEmulatedWakeOnAddress; gRuntimeConfig.threadingConfig = decltype(gRuntimeConfig.threadingConfig)(cpy);