diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 8e9d550040..c7fad44dbc 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -4811,6 +4811,7 @@ bool spu_thread::stop_and_signal(u32 code) { queue->sq.emplace_back(this); group->run_state = SPU_THREAD_GROUP_STATUS_WAITING; + group->waiter_spu_index = index; for (auto& thread : group->threads) { diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 01e95ffa4d..ff1c8cd9d9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -228,19 +228,35 @@ lv2_spu_group::lv2_spu_group(utils::serial& ar) noexcept *ep = idm::get_unlocked(ar.operator u32()); } + u32 waiter_spu_index = -1; + switch (run_state) { // Commented stuff are handled by different means currently //case SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED: //case SPU_THREAD_GROUP_STATUS_INITIALIZED: //case SPU_THREAD_GROUP_STATUS_READY: - //case SPU_THREAD_GROUP_STATUS_WAITING: + case SPU_THREAD_GROUP_STATUS_WAITING: + { + run_state = SPU_THREAD_GROUP_STATUS_RUNNING; + ar(waiter_spu_index); + [[fallthrough]]; + } + case SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED: + { + if (run_state == SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED) + { + run_state = SPU_THREAD_GROUP_STATUS_SUSPENDED; + } + + [[fallthrough]]; + } case SPU_THREAD_GROUP_STATUS_SUSPENDED: { - // Suspend all SPU threads + // Suspend all SPU threads except a thread that waits on sys_spu_thread_receive_event for (const auto& thread : threads) { - if (thread) + if (thread && thread->index != waiter_spu_index) { thread->state += cpu_flag::suspend; } @@ -263,28 +279,7 @@ void lv2_spu_group::save(utils::serial& ar) { USING_SERIALIZATION_VERSION(spu); - spu_group_status _run_state = run_state; - - switch (_run_state) - { - // Commented stuff are handled by different means currently - //case SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED: - //case SPU_THREAD_GROUP_STATUS_INITIALIZED: - //case SPU_THREAD_GROUP_STATUS_READY: - - // Waiting SPU should recover this - case SPU_THREAD_GROUP_STATUS_WAITING: _run_state = SPU_THREAD_GROUP_STATUS_RUNNING; break; - case SPU_THREAD_GROUP_STATUS_WAITING_AND_SUSPENDED: _run_state = SPU_THREAD_GROUP_STATUS_SUSPENDED; break; - //case SPU_THREAD_GROUP_STATUS_RUNNING: - //case SPU_THREAD_GROUP_STATUS_STOPPED: - //case SPU_THREAD_GROUP_STATUS_UNKNOWN: - default: - { - break; - } - } - - ar(name, max_num, mem_size, type, ct->id, has_scheduler_context, max_run, init, prio, _run_state, exit_status); + ar(name, max_num, mem_size, type, ct->id, has_scheduler_context, max_run, init, prio, run_state, exit_status); for (const auto& thread : threads) { @@ -305,6 +300,11 @@ void lv2_spu_group::save(utils::serial& ar) { ar(lv2_obj::check(*ep) ? (*ep)->id : 0); } + + if (run_state == SPU_THREAD_GROUP_STATUS_WAITING) + { + ar(waiter_spu_index); + } } lv2_spu_image::lv2_spu_image(utils::serial& ar) diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index e5f12108db..05524b3072 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -290,6 +290,7 @@ struct lv2_spu_group 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; + u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall class ppu_thread* waiter = nullptr; bool set_terminate = false;