From 85d16496969e3d22d2c5a03405da09d6b5e9dfcd Mon Sep 17 00:00:00 2001 From: Elad <18193363+elad335@users.noreply.github.com> Date: Sat, 2 Nov 2024 08:36:35 +0200 Subject: [PATCH] utils/atomic.hpp: Make atomic_op reject non-non-const lvalue --- rpcs3/Emu/Cell/Modules/cellSync.cpp | 12 ++++++------ rpcs3/Emu/Cell/SPUThread.cpp | 4 ++-- rpcs3/Emu/Cell/lv2/lv2.cpp | 2 +- rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp | 4 ++-- rpcs3/util/atomic.cpp | 8 ++++---- rpcs3/util/atomic.hpp | 30 +++++++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 15 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellSync.cpp b/rpcs3/Emu/Cell/Modules/cellSync.cpp index 5f281e3fed..99adf97c02 100644 --- a/rpcs3/Emu/Cell/Modules/cellSync.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync.cpp @@ -472,7 +472,7 @@ error_code cellSyncQueuePush(ppu_thread& ppu, vm::ptr queue, vm:: u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_push_begin(ctrl, depth, &position); })) @@ -509,7 +509,7 @@ error_code cellSyncQueueTryPush(vm::ptr queue, vm::cptr buf u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_push_begin(ctrl, depth, &position); })) @@ -543,7 +543,7 @@ error_code cellSyncQueuePop(ppu_thread& ppu, vm::ptr queue, vm::p u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_pop_begin(ctrl, depth, &position); })) @@ -580,7 +580,7 @@ error_code cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffe u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_pop_begin(ctrl, depth, &position); })) @@ -614,7 +614,7 @@ error_code cellSyncQueuePeek(ppu_thread& ppu, vm::ptr queue, vm:: u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_peek_begin(ctrl, depth, &position); })) @@ -651,7 +651,7 @@ error_code cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buff u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_peek_begin(ctrl, depth, &position); })) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 6a836e93ac..77f976d51a 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2698,7 +2698,7 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* bool ok = false; - std::tie(old, ok) = bits->fetch_op([&](auto& v) + std::tie(old, ok) = bits->fetch_op([&](u128& v) { if (v & wmask) { @@ -2796,7 +2796,7 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* res += 127; // Release bits and notify - bits->atomic_op([&](auto& v) + bits->atomic_op([&](u128& v) { v &= ~wmask; }); diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index e4ed28fbcd..d30a516607 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1852,7 +1852,7 @@ void lv2_obj::schedule_all(u64 current_time) target->start_time = 0; - if ((target->state.fetch_op(FN(x += cpu_flag::signal, x -= cpu_flag::suspend, x-= remove_yield, void())) & (cpu_flag::wait + cpu_flag::signal)) != cpu_flag::wait) + if ((target->state.fetch_op(AOFN(x += cpu_flag::signal, x -= cpu_flag::suspend, x-= remove_yield, void())) & (cpu_flag::wait + cpu_flag::signal)) != cpu_flag::wait) { continue; } diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 20a210cbcb..7df939b738 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -142,7 +142,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout) const auto mutex = idm::get(lwmutex_id, [&, notify = lv2_obj::notify_all_t()](lv2_lwmutex& mutex) { - if (s32 signal = mutex.lv2_control.fetch_op([](auto& data) + if (s32 signal = mutex.lv2_control.fetch_op([](lv2_lwmutex::control_data_t& data) { if (data.signaled) { @@ -297,7 +297,7 @@ error_code _sys_lwmutex_trylock(ppu_thread& ppu, u32 lwmutex_id) const auto mutex = idm::check(lwmutex_id, [&](lv2_lwmutex& mutex) { - auto [_, ok] = mutex.lv2_control.fetch_op([](auto& data) + auto [_, ok] = mutex.lv2_control.fetch_op([](lv2_lwmutex::control_data_t& data) { if (data.signaled & 1) { diff --git a/rpcs3/util/atomic.cpp b/rpcs3/util/atomic.cpp index 06b61c7927..41b28d1d40 100644 --- a/rpcs3/util/atomic.cpp +++ b/rpcs3/util/atomic.cpp @@ -434,7 +434,7 @@ static u32 cond_alloc(uptr iptr, u32 tls_slot = -1) }); // Set lowest clear bit - const u64 bits = s_cond_bits[level3].fetch_op(FN(x |= x + 1, void())); + const u64 bits = s_cond_bits[level3].fetch_op(AOFN(x |= x + 1, void())); // Find lowest clear bit (before it was set in fetch_op) const u32 id = level3 * 64 + std::countr_one(bits); @@ -503,9 +503,9 @@ static void cond_free(u32 cond_id, u32 tls_slot = -1) // Release the semaphore tree in the reverse order s_cond_bits[cond_id / 64] &= ~(1ull << (cond_id % 64)); - s_cond_sem3[level2].atomic_op(FN(x -= u128{1} << (level3 * 7))); - s_cond_sem2[level1].atomic_op(FN(x -= u128{1} << (level2 * 11))); - s_cond_sem1.atomic_op(FN(x -= u128{1} << (level1 * 14))); + s_cond_sem3[level2].atomic_op(AOFN(x -= u128{1} << (level3 * 7))); + s_cond_sem2[level1].atomic_op(AOFN(x -= u128{1} << (level2 * 11))); + s_cond_sem1.atomic_op(AOFN(x -= u128{1} << (level1 * 14))); } static cond_handle* cond_id_lock(u32 cond_id, uptr iptr = 0) diff --git a/rpcs3/util/atomic.hpp b/rpcs3/util/atomic.hpp index abc4df9445..2d4946a04a 100644 --- a/rpcs3/util/atomic.hpp +++ b/rpcs3/util/atomic.hpp @@ -1233,6 +1233,7 @@ public: // Atomic operation; returns old value, or pair of old value and return value (cancel op if evaluates to false) template > + requires (!std::is_invocable_v && !std::is_invocable_v) std::conditional_t, type, std::pair> fetch_op(F func) { type _new, old = atomic_storage::load(m_data); @@ -1264,6 +1265,7 @@ public: // Atomic operation; returns function result value, function is the lambda template > + requires (!std::is_invocable_v && !std::is_invocable_v) RT atomic_op(F func) { type _new, old = atomic_storage::load(m_data); @@ -1798,3 +1800,31 @@ struct std::common_type> : std::common_type + struct aofn_helper + { + F f; + + aofn_helper(F&& f) noexcept + : f(std::forward(f)) + { + } + + template requires (std::is_same_v, std::remove_cvref_t> && !std::is_rvalue_reference_v) + auto operator()(Arg& arg) const noexcept + { + return f(std::forward(arg)); + } + }; + + template + aofn_helper(F&& f) -> aofn_helper; +} + +// Shorter lambda for non-cv qualified L-values +// For use with atomic operations +#define AOFN(...) \ + ::utils::aofn_helper([&](auto& x) { return (__VA_ARGS__); })