From a3007e11ca28e98b97409aa26b27593fcb8fd81f Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 11 Aug 2022 17:40:11 +0300 Subject: [PATCH] SPU: Fix minor race in sys_spu_thread_receive_event Check final cpu_state::state value for suspend state because that's the variable the thread waits on. --- rpcs3/Emu/Cell/SPUThread.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 7f4049cd83..f35766ff2d 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -4778,12 +4778,10 @@ bool spu_thread::stop_and_signal(u32 code) while (true) { - // Check group status, wait if necessary - for (auto _state = +group->run_state; - _state >= SPU_THREAD_GROUP_STATUS_WAITING && _state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED; - _state = group->run_state) + // Check group status (by actually checking thread status), wait if necessary + while (true) { - const auto old = state.load(); + const auto old = +state; if (is_stopped(old)) { @@ -4791,7 +4789,13 @@ bool spu_thread::stop_and_signal(u32 code) return false; } - thread_ctrl::wait_on(state, old);; + if (!is_paused(old)) + { + // The group is not suspended (anymore) + break; + } + + thread_ctrl::wait_on(state, old); } reader_lock{group->mutex}, queue = get_queue(spuq); @@ -4819,6 +4823,7 @@ bool spu_thread::stop_and_signal(u32 code) if (group->run_state >= SPU_THREAD_GROUP_STATUS_WAITING && group->run_state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED) { // Try again + ensure(state & cpu_flag::suspend); continue; } @@ -4989,19 +4994,25 @@ bool spu_thread::stop_and_signal(u32 code) while (true) { - for (auto _state = +group->run_state; - _state >= SPU_THREAD_GROUP_STATUS_WAITING && _state <= SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED; - _state = group->run_state) + // Check group status (by actually checking thread status), wait if necessary + while (true) { const auto old = +state; if (is_stopped(old)) { ch_out_mbox.set_value(value); + state += cpu_flag::again; return false; } - thread_ctrl::wait_on(state, old);; + if (!is_paused(old)) + { + // The group is not suspended (anymore) + break; + } + + thread_ctrl::wait_on(state, old); } std::lock_guard lock(group->mutex);