diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index c6e179b001..bf325019c4 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1603,6 +1603,7 @@ void spu_thread::cpu_return() if (ensure(group->running)-- == 1) { + u32 last_stop = 0; { lv2_obj::notify_all_t notify; std::lock_guard lock(group->mutex); @@ -1632,7 +1633,17 @@ void spu_thread::cpu_return() exit_status.set_value(last_exit_status); } - group->stop_count++; + last_stop = group->stop_count; + + if (last_stop == umax) + { + // Restart with some high count to preserve some meaning + group->stop_count = 1000; + } + else + { + group->stop_count++; + } if (const auto ppu = std::exchange(group->waiter, nullptr)) { @@ -1646,6 +1657,12 @@ void spu_thread::cpu_return() // Notify on last thread stopped group->stop_count.notify_all(); + + // Wait for terminators manually if needed (ensuring they quit before value-wrapping) + while (last_stop == umax && group->wait_term_count) + { + std::this_thread::yield(); + } } 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 6743ddf718..79de82f106 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -1352,7 +1352,8 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) if (group->set_terminate) { // Wait for termination, only then return error code - const u64 last_stop = group->stop_count; + const u32 last_stop = group->stop_count; + group->wait_term_count++; lock.unlock(); short_sleep(ppu); @@ -1361,6 +1362,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) group->stop_count.wait(last_stop); } + group->wait_term_count--; return CELL_ESTAT; } @@ -1414,7 +1416,8 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) group->join_state = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED; // Wait until the threads are actually stopped - const u64 last_stop = group->stop_count; + const u32 last_stop = group->stop_count; + group->wait_term_count++; lock.unlock(); short_sleep(ppu); @@ -1423,6 +1426,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) group->stop_count.wait(last_stop); } + group->wait_term_count--; return CELL_OK; } diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index cfeed37c53..690a273f4c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -289,7 +289,8 @@ 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 = 0; // Number of running threads - atomic_t stop_count = 0; + atomic_t stop_count = 0; + atomic_t wait_term_count = 0; u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall class ppu_thread* waiter = nullptr; bool set_terminate = false;