diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 211e5b2924..86ec0f92ef 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -5,6 +5,7 @@ #include "Emu/System.h" #include "Emu/system_config.h" #include "Emu/Memory/vm_locking.h" +#include "Emu/Memory/vm_reservation.h" #include "Emu/IdManager.h" #include "Emu/GDB.h" #include "Emu/Cell/PPUThread.h" @@ -892,6 +893,14 @@ cpu_thread& cpu_thread::operator=(thread_state) if (old & cpu_flag::wait && old.none_of(cpu_flag::again + cpu_flag::exit)) { state.notify_one(cpu_flag::exit); + + if (auto thread = try_get()) + { + if (u32 resv = atomic_storage::load(thread->raddr)) + { + vm::reservation_notifier(resv).notify_one(); + } + } } return *this; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 9a59ca6a28..45257697a5 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -4336,6 +4336,14 @@ s64 spu_thread::get_ch_value(u32 ch) return true; }); + if (raddr - spurs_addr <= 0x80 && !g_cfg.core.spu_accurate_reservations && mask1 == SPU_EVENT_LR) + { + // Wait without timeout, in this situation we have notifications for all writes making it possible + // Abort notifications are handled specially for performance reasons + vm::reservation_notifier(raddr).wait(rtime, -128); + continue; + } + vm::reservation_notifier(raddr).wait(rtime, -128, atomic_wait_timeout{80'000}); } else @@ -5219,6 +5227,8 @@ bool spu_thread::stop_and_signal(u32 code) break; } + u32 prev_resv = 0; + for (auto& thread : group->threads) { if (thread) @@ -5227,10 +5237,26 @@ bool spu_thread::stop_and_signal(u32 code) if (thread.get() != this && thread->state & cpu_flag::ret) { thread_ctrl::notify(*thread); + + if (u32 resv = atomic_storage::load(thread->raddr)) + { + if (prev_resv && prev_resv != resv) + { + // Batch reservation notifications if possible + vm::reservation_notifier(prev_resv).notify_all(); + } + + prev_resv = resv; + } } } } - + + if (prev_resv) + { + vm::reservation_notifier(prev_resv).notify_all(); + } + check_state(); return true; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 9d5a398606..06f288e6ca 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -14,6 +14,7 @@ #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/RawSPUThread.h" #include "Emu/Cell/timers.hpp" +#include "Emu/Memory/vm_reservation.h" #include "sys_interrupt.h" #include "sys_process.h" #include "sys_memory.h" @@ -1365,14 +1366,32 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) } } + u32 prev_resv = 0; + for (auto& thread : group->threads) { while (thread && group->running && thread->state & cpu_flag::wait) { thread_ctrl::notify(*thread); + + if (u32 resv = atomic_storage::load(thread->raddr)) + { + if (prev_resv && prev_resv != resv) + { + // Batch reservation notifications if possible + vm::reservation_notifier(prev_resv).notify_all(); + } + + prev_resv = resv; + } } } + if (prev_resv) + { + vm::reservation_notifier(prev_resv).notify_all(); + } + group->exit_status = value; group->join_state = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;