diff --git a/Source/Threading/Primitives/AuSemaphore.Linux.cpp b/Source/Threading/Primitives/AuSemaphore.Linux.cpp index 28bed5ae..622bc92a 100644 --- a/Source/Threading/Primitives/AuSemaphore.Linux.cpp +++ b/Source/Threading/Primitives/AuSemaphore.Linux.cpp @@ -14,7 +14,7 @@ namespace Aurora::Threading::Primitives { - SemaphoreImpl::SemaphoreImpl(long intialValue) : value_(intialValue) + SemaphoreImpl::SemaphoreImpl(long intialValue) : dwState_(intialValue) { } @@ -33,12 +33,17 @@ namespace Aurora::Threading::Primitives return true; } + bool SemaphoreImpl::TryLockNoSpin() + { + auto old = this->dwState_; + return (old != 0 && AuAtomicCompareExchange(&this->dwState_, old - 1, old) == old); + } + bool SemaphoreImpl::TryLock() { return DoTryIf([=]() { - auto old = this->value_; - return (old != 0 && AuAtomicCompareExchange(&this->value_, old - 1, old) == old); + return this->TryLockNoSpin(); }); } @@ -68,22 +73,25 @@ namespace Aurora::Threading::Primitives Time::monoabsns2ts(&tspec, uEnd); } - auto old = this->value_; + AuAtomicAdd(&this->dwSleeping_, 1u); + + auto old = this->dwState_; //!tryLock (with old in a scope we can access) while (!((old != 0) && - (AuAtomicCompareExchange(&this->value_, old - 1, old) == old))) + (AuAtomicCompareExchange(&this->dwState_, old - 1, old) == old))) { if (uTimeout != 0) { if (Time::SteadyClockNS() >= uEnd) { + AuAtomicSub(&this->dwSleeping_, 1u); return false; } int ret {}; do { - ret = futex_wait(&this->value_, 0, &tspec); + ret = futex_wait(&this->dwState_, 0, &tspec); } while (ret == EINTR); } @@ -94,7 +102,7 @@ namespace Aurora::Threading::Primitives do { - if ((ret = futex_wait(&this->value_, 0)) == 0) + if ((ret = futex_wait(&this->dwState_, 0)) == 0) { bStatus = true; continue; @@ -112,9 +120,10 @@ namespace Aurora::Threading::Primitives RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "semaphore wait failed: {}", ret) } - old = this->value_; + old = this->dwState_; } + AuAtomicSub(&this->dwSleeping_, 1u); return true; } @@ -126,8 +135,11 @@ namespace Aurora::Threading::Primitives void SemaphoreImpl::Unlock(long count) { - AuAtomicAdd(&this->value_, count); - futex_wake(&this->value_, count); + AuAtomicAdd(&this->dwState_, count); + if (this->dwSleeping_) + { + futex_wake(&this->dwState_, count); + } } void SemaphoreImpl::Unlock() diff --git a/Source/Threading/Primitives/AuSemaphore.Linux.hpp b/Source/Threading/Primitives/AuSemaphore.Linux.hpp index ec9734df..ee8c1b65 100644 --- a/Source/Threading/Primitives/AuSemaphore.Linux.hpp +++ b/Source/Threading/Primitives/AuSemaphore.Linux.hpp @@ -14,6 +14,7 @@ namespace Aurora::Threading::Primitives SemaphoreImpl(long intialValue = 0); ~SemaphoreImpl(); + bool TryLockNoSpin(); bool HasOSHandle(AuMach &mach) override; bool HasLockImplementation() override; bool TryLock() override; @@ -24,6 +25,7 @@ namespace Aurora::Threading::Primitives void Unlock() override; private: - AuUInt32 value_ {}; + AuUInt32 dwState_ {}; + AuUInt32 dwSleeping_ {}; }; } \ No newline at end of file