From 4b0a7c651a5b719c221a2590722e1623e30e8b77 Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Tue, 12 Sep 2023 16:12:54 +0100 Subject: [PATCH] [*] Guess I should finalize this for linux. The verbosity of writing a cas in the wait loops is stupid if we arent doing anything special with the bits. --- .../Primitives/AuConditionMutex.Linux.cpp | 18 ++-- Source/Threading/Primitives/AuMutex.Linux.cpp | 86 +++++++++++++++++-- Source/Threading/Primitives/AuMutex.Linux.hpp | 1 + .../Primitives/AuSemaphore.Linux.cpp | 7 +- 4 files changed, 87 insertions(+), 25 deletions(-) diff --git a/Source/Threading/Primitives/AuConditionMutex.Linux.cpp b/Source/Threading/Primitives/AuConditionMutex.Linux.cpp index a9c24f14..193a7c92 100644 --- a/Source/Threading/Primitives/AuConditionMutex.Linux.cpp +++ b/Source/Threading/Primitives/AuConditionMutex.Linux.cpp @@ -75,9 +75,7 @@ namespace Aurora::Threading::Primitives AuAtomicAdd(&this->uSleeping_, 1u); - auto state = this->uState_; - while (!(state == 0 && - AuAtomicCompareExchange(&this->uState_, 1, state) == state)) + while (!this->TryLockNoSpin()) { if (uTimeout != 0) { @@ -90,7 +88,7 @@ namespace Aurora::Threading::Primitives int ret {}; do { - ret = futex_wait(&this->uState_, state, &tspec); + ret = futex_wait(&this->uState_, 1, &tspec); } while (ret == -EINTR); } @@ -101,7 +99,7 @@ namespace Aurora::Threading::Primitives do { - if ((ret = futex_wait(&this->uState_, state)) == 0) + if ((ret = futex_wait(&this->uState_, 1)) == 0) { bStatus = true; break; @@ -118,8 +116,6 @@ namespace Aurora::Threading::Primitives RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "Mutex wait failed: {}", ret) } - - state = this->uState_; } AuAtomicSub(&this->uSleeping_, 1u); @@ -170,9 +166,7 @@ namespace Aurora::Threading::Primitives AuAtomicAdd(&this->uSleeping_, 1u); - auto state = this->uState_; - while (!(state == 0 && - AuAtomicCompareExchange(&this->uState_, 1, state) == state)) + while (!this->TryLockNoSpin()) { int ret {}; @@ -180,7 +174,7 @@ namespace Aurora::Threading::Primitives do { - if ((ret = futex_wait(&this->uState_, state)) == 0) + if ((ret = futex_wait(&this->uState_, 1)) == 0) { bStatus = true; break; @@ -196,8 +190,6 @@ namespace Aurora::Threading::Primitives while (ret == -EINTR); RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "Mutex wait failed: {}", ret) - - state = this->uState_; } AuAtomicSub(&this->uSleeping_, 1u); diff --git a/Source/Threading/Primitives/AuMutex.Linux.cpp b/Source/Threading/Primitives/AuMutex.Linux.cpp index 53af0c33..1b409fa2 100755 --- a/Source/Threading/Primitives/AuMutex.Linux.cpp +++ b/Source/Threading/Primitives/AuMutex.Linux.cpp @@ -101,9 +101,7 @@ namespace Aurora::Threading::Primitives Time::monoabsns2ts(&tspec, uEnd); } - auto state = this->state_; - while (!(state == 0 && - AuAtomicCompareExchange(&this->state_, 1, state) == state)) + while (!this->TryLockNoSpin()) { if (uTimeout != 0) { @@ -116,7 +114,7 @@ namespace Aurora::Threading::Primitives int ret {}; do { - ret = futex_wait(&this->state_, state, &tspec); + ret = futex_wait(&this->state_, 1, &tspec); } while (ret == -EINTR); } @@ -127,7 +125,7 @@ namespace Aurora::Threading::Primitives do { - if ((ret = futex_wait(&this->state_, state)) == 0) + if ((ret = futex_wait(&this->state_, 1)) == 0) { bStatus = true; break; @@ -144,8 +142,84 @@ namespace Aurora::Threading::Primitives RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "Mutex wait failed: {}", ret) } + } - state = this->state_; + AuAtomicSub(&this->dwSleeping_, 1u); + return true; + } + + bool MutexImpl::LockAbsNS(AuUInt64 uTimeout) + { + struct timespec tspec; + + if (this->TryLockNoSpin()) + { + return true; + } + + if (uTimeout != 0) + { + Time::monoabsns2ts(&tspec, uTimeout); + } + + if (ThrdCfg::gPreferLinuxPrimitivesFutexNoSpin) + { + if (this->TryLockNoSpin()) + { + return true; + } + } + else + { + if (this->TryLockHeavy()) + { + return true; + } + } + + AuAtomicAdd(&this->dwSleeping_, 1u); + + while (!this->TryLockNoSpin()) + { + if (uTimeout != 0) + { + if (Time::SteadyClockNS() >= uTimeout) + { + AuAtomicSub(&this->dwSleeping_, 1u); + return false; + } + + int ret {}; + do + { + ret = futex_wait(&this->state_, 1, &tspec); + } + while (ret == -EINTR); + } + else + { + int ret {}; + bool bStatus {}; + + do + { + if ((ret = futex_wait(&this->state_, 1)) == 0) + { + bStatus = true; + break; + } + + if (ret == -EAGAIN) + { + bStatus = true; + break; + } + + } + while (ret == -EINTR); + + RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "Mutex wait failed: {}", ret) + } } AuAtomicSub(&this->dwSleeping_, 1u); diff --git a/Source/Threading/Primitives/AuMutex.Linux.hpp b/Source/Threading/Primitives/AuMutex.Linux.hpp index 2b70ccdd..f8fb2ba5 100755 --- a/Source/Threading/Primitives/AuMutex.Linux.hpp +++ b/Source/Threading/Primitives/AuMutex.Linux.hpp @@ -20,6 +20,7 @@ namespace Aurora::Threading::Primitives void SlowLock() override; bool LockMS(AuUInt64 timeout) override; bool LockNS(AuUInt64 timeout) override; + bool LockAbsNS(AuUInt64 uTimeout); void Unlock() override; auline bool TryLockNoSpin(); diff --git a/Source/Threading/Primitives/AuSemaphore.Linux.cpp b/Source/Threading/Primitives/AuSemaphore.Linux.cpp index dac66420..562f35ab 100644 --- a/Source/Threading/Primitives/AuSemaphore.Linux.cpp +++ b/Source/Threading/Primitives/AuSemaphore.Linux.cpp @@ -192,10 +192,7 @@ namespace Aurora::Threading::Primitives AuAtomicAdd(&this->dwSleeping_, 1u); - auto old = this->dwState_; - //!tryLock (with old in a scope we can access) - while (!((old != 0) && - (AuAtomicCompareExchange(&this->dwState_, old - 1, old) == old))) + while (!this->TryLockNoSpin()) { if (uTimeout != 0) { @@ -236,8 +233,6 @@ namespace Aurora::Threading::Primitives RUNTIME_ASSERT_SHUTDOWN_SAFE(bStatus, "semaphore wait failed: {}", ret) } - - old = this->dwState_; } AuAtomicSub(&this->dwSleeping_, 1u);