diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 2a6864f8cc..15bbe78db9 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -521,6 +521,11 @@ void spu_thread::cpu_stop() group->stop_count++; group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; + if (!group->join_state) + { + group->join_state = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; + } + if (const auto ppu = std::exchange(group->waiter, nullptr)) { // Send exit status directly to the joining thread @@ -2436,7 +2441,7 @@ bool spu_thread::stop_and_signal(u32 code) } group->exit_status = value; - group->join_state |= SPU_TGJSF_GROUP_EXIT; + group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT; state += cpu_flag::stop; return true; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 1c84648034..d1361437be 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -607,7 +607,7 @@ error_code sys_spu_thread_group_terminate(u32 id, s32 value) } group->exit_status = value; - group->join_state |= SPU_TGJSF_TERMINATED; + group->join_state = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED; // Wait until the threads are actually stopped const u64 last_stop = group->stop_count - !group->running; @@ -648,11 +648,12 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause return CELL_EBUSY; } - if (group->run_state == SPU_THREAD_GROUP_STATUS_INITIALIZED) + if (group->join_state) { - // Already terminated + // Already signaled ppu.gpr[4] = group->join_state; ppu.gpr[5] = group->exit_status; + group->join_state.release(0); break; } else @@ -661,11 +662,9 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause group->waiter = &ppu; } - const u64 last_stop = group->stop_count - !group->running; - lv2_obj::sleep(ppu); - while (group->stop_count == last_stop) + while (!group->join_state) { if (ppu.is_stopped()) { @@ -674,6 +673,8 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause group->cond.wait(lock); } + + group->join_state.release(0); } while (0); @@ -682,27 +683,9 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause return 0; } - switch (ppu.gpr[4] & (SPU_TGJSF_GROUP_EXIT | SPU_TGJSF_TERMINATED)) + if (cause) { - case 0: - { - if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT; - break; - } - case SPU_TGJSF_GROUP_EXIT: - { - if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT; - break; - } - case SPU_TGJSF_TERMINATED: - { - if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED; - break; - } - default: - { - fmt::throw_exception("Unexpected join_state" HERE); - } + *cause = static_cast(ppu.gpr[4]); } if (status) diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 8a90656af0..adfdabba62 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -207,13 +207,6 @@ enum : u32 SYS_SPU_IMAGE_DIRECT = 1, }; -// SPU Thread Group Join State Flag -enum : u32 -{ - SPU_TGJSF_TERMINATED = (1 << 1), // set if SPU Thread Group is terminated by sys_spu_thread_group_terminate - SPU_TGJSF_GROUP_EXIT = (1 << 2), // set if SPU Thread Group is terminated by sys_spu_thread_group_exit -}; - struct lv2_spu_group { static const u32 id_base = 1; // Wrong? @@ -232,7 +225,7 @@ struct lv2_spu_group atomic_t prio; // SPU Thread Group Priority atomic_t run_state; // SPU Thread Group State atomic_t exit_status; // SPU Thread Group Exit Status - atomic_t join_state; // flags used to detect exit cause + 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;