From 7a4ee286be39e9544a96323e24ca86b91c87aa49 Mon Sep 17 00:00:00 2001 From: Eladash Date: Mon, 11 Sep 2023 12:52:10 +0300 Subject: [PATCH] Rewrite Utilitis/sema.cpp --- Utilities/sema.cpp | 70 +++++++++++++++++++++--------------- Utilities/sema.h | 49 +++++++++++++++++-------- rpcs3/Emu/Cell/PPUThread.cpp | 8 ++--- 3 files changed, 79 insertions(+), 48 deletions(-) diff --git a/Utilities/sema.cpp b/Utilities/sema.cpp index faf082b761..ee3dd98ffa 100644 --- a/Utilities/sema.cpp +++ b/Utilities/sema.cpp @@ -8,72 +8,84 @@ void semaphore_base::imp_wait() { busy_wait(); - const s32 value = m_value.load(); + const u32 value = m_value.load(); - if (value > 0 && m_value.compare_and_swap_test(value, value - 1)) + if (value & c_value_mask && m_value.compare_and_swap_test(value, value - c_value)) { return; } } + bool waits = false; + while (true) { // Try hard way - const s32 value = m_value.atomic_op([](s32& value) + const u32 value = m_value.fetch_op([&](u32& value) { - // Use sign bit to acknowledge waiter presence - if (value && value > smin) - { - value--; + ensure(value != c_waiter_mask); // "semaphore_base: overflow" - if (value < 0) + if (value & c_value_mask) + { + // Obtain signal + value -= c_value; + + if (waits) { - // Remove sign bit - value -= s32{smin}; + // Remove waiter + value -= c_waiter; } } - else + else if (!waits) { - // Set sign bit - value = smin; + // Add waiter + value += c_waiter; } - - return value; }); - if (value >= 0) + if (value & c_value_mask) { - // Signal other waiter to wake up or to restore sign bit - m_value.notify_one(); - return; + break; } - m_value.wait(value); + m_value.wait(value + (waits ? 0 : c_waiter)); + waits = true; } } -void semaphore_base::imp_post(s32 _old) +void semaphore_base::imp_post(u32 _old) { - ensure(_old < 0); // "semaphore_base: overflow" + ensure(~_old & c_value_mask); // "semaphore_base: overflow" - m_value.notify_one(); + if ((_old & c_waiter_mask) / c_waiter > (_old & c_value_mask) / c_value) + { + m_value.notify_one(); + } } -bool semaphore_base::try_post(s32 _max) +bool semaphore_base::try_post(u32 _max) { // Conditional increment - const s32 value = m_value.fetch_op([&](s32& value) + const auto [value, ok] = m_value.fetch_op([&](u32& value) { - if (value < _max) + if ((value & c_value_mask) <= _max) { - value += 1; + value += c_value; + return true; } + + return false; }); - if (value < 0) + if (!ok) + { + return false; + } + + if (value & c_waiter_mask) { imp_post(value); } - return value < _max; + return true; } diff --git a/Utilities/sema.h b/Utilities/sema.h index 6e067e419f..45080ebed2 100644 --- a/Utilities/sema.h +++ b/Utilities/sema.h @@ -7,14 +7,22 @@ class semaphore_base { // Semaphore value - atomic_t m_value; + atomic_t m_value; + + enum : u32 + { + c_value = 1u << 0, + c_value_mask = +c_value * 0xffff, + c_waiter = 1u << 16, + c_waiter_mask = +c_waiter * 0xffff, + }; void imp_wait(); - void imp_post(s32 _old); + void imp_post(u32 _old); protected: - explicit constexpr semaphore_base(s32 value) + explicit constexpr semaphore_base(u32 value) noexcept : m_value{value} { } @@ -22,10 +30,10 @@ protected: void wait() { // Load value - const s32 value = m_value.load(); + const u32 value = m_value.load(); // Conditional decrement - if (value <= 0 || !m_value.compare_and_swap_test(value, value - 1)) [[unlikely]] + if ((value & c_value_mask) == 0 || !m_value.compare_and_swap_test(value, value - c_value)) [[unlikely]] { imp_wait(); } @@ -33,36 +41,47 @@ protected: bool try_wait() { - return m_value.try_dec(0); + return m_value.fetch_op([](u32& value) + { + if (value & c_value_mask) + { + value -= c_value; + return true; + } + + return false; + }).second; } - void post(s32 _max) + void post(u32 _max) { // Unconditional increment - const s32 value = m_value.fetch_add(1); + const u32 value = m_value.fetch_add(c_value); - if (value < 0 || value >= _max) [[unlikely]] + if (value & c_waiter_mask || (value & c_value_mask) >= std::min(c_value_mask, _max)) [[unlikely]] { imp_post(value); } } - bool try_post(s32 _max); + bool try_post(u32 _max); public: // Get current semaphore value s32 get() const { // Load value - const s32 value = m_value; + const u32 raw_value = m_value; + const u32 waiters = (raw_value & c_waiter_mask) / c_waiter; + const u32 value = (raw_value & c_value_mask) / c_value; // Return only positive value - return value < 0 ? 0 : value; + return static_cast(waiters >= value ? 0 : value - waiters); } }; // Lightweight semaphore template (default arguments define binary semaphore and Def == Max) -template +template class semaphore final : public semaphore_base { static_assert(Max >= 0, "semaphore<>: Max is out of bounds"); @@ -73,13 +92,13 @@ class semaphore final : public semaphore_base public: // Default constructor (recommended) - constexpr semaphore() + constexpr semaphore() noexcept : base(Def) { } // Explicit value constructor (not recommended) - explicit constexpr semaphore(s32 value) + explicit constexpr semaphore(s16 value) noexcept : base(value) { } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 9cf6049b9b..fb54501c45 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -3420,14 +3420,14 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value) struct jit_core_allocator { - const s32 thread_count = g_cfg.core.llvm_threads ? std::min(g_cfg.core.llvm_threads, limit()) : limit(); + const s16 thread_count = g_cfg.core.llvm_threads ? std::min(g_cfg.core.llvm_threads, limit()) : limit(); // Initialize global semaphore with the max number of threads - ::semaphore<0x7fffffff> sem{std::max(thread_count, 1)}; + ::semaphore<0x7fff> sem{std::max(thread_count, 1)}; - static s32 limit() + static s16 limit() { - return static_cast(utils::get_thread_count()); + return static_cast(std::min(0x7fff, utils::get_thread_count())); } };