diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 7d64cd862..f6c3e122c 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -983,7 +983,6 @@ void spu_thread::cpu_stop() { { std::lock_guard lock(group->mutex); - group->stop_count++; group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; if (!group->join_state) @@ -1010,17 +1009,20 @@ void spu_thread::cpu_stop() exit_status.set_value(last_exit_status); } + group->stop_count++; + if (const auto ppu = std::exchange(group->waiter, nullptr)) { // Send exit status directly to the joining thread ppu->gpr[4] = group->join_state; ppu->gpr[5] = group->exit_status; group->join_state.release(0); + lv2_obj::awake(ppu); } } // Notify on last thread stopped - group->cond.notify_all(); + group->stop_count.notify_all(); } else if (status_npc.load().status >> 16 == SYS_SPU_THREAD_STOP_THREAD_EXIT) { diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 56114f3d1..81e7af8cd 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -978,10 +978,11 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) { // Wait for termination, only then return error code const u64 last_stop = group->stop_count; + lock.unlock(); while (group->stop_count == last_stop) { - group->cond.wait(lock); + group->stop_count.wait(last_stop); } return CELL_ESTAT; @@ -1010,10 +1011,11 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) // Wait until the threads are actually stopped const u64 last_stop = group->stop_count; + lock.unlock(); while (group->stop_count == last_stop) { - group->cond.wait(lock); + group->stop_count.wait(last_stop); } return CELL_OK; @@ -1065,29 +1067,24 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause else { // Subscribe to receive status in r4-r5 - ppu.gpr[4] = 0; group->waiter = &ppu; } lv2_obj::sleep(ppu); + lock.unlock(); - while (!ppu.gpr[4]) + while (!ppu.state.test_and_reset(cpu_flag::signal)) { if (ppu.is_stopped()) { return 0; } - group->cond.wait(lock); + thread_ctrl::wait(); } } while (0); - if (ppu.test_stopped()) - { - return 0; - } - if (!cause) { if (status) diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 0f04d4733..50b29895e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -278,7 +278,6 @@ struct lv2_spu_group atomic_t exit_status; // SPU Thread Group Exit Status atomic_t join_state; // flags used to detect exit cause and signal atomic_t running; // Number of running threads - cond_variable cond; // used to signal waiting PPU thread atomic_t stop_count; class ppu_thread* waiter = nullptr; bool set_terminate = false;