diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 27d1b7fa20..bdf4ba6a5a 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Utilities/JIT.h" #include "Utilities/sysinfo.h" #include "Emu/Memory/vm.h" @@ -480,6 +480,21 @@ extern thread_local std::string(*g_tls_log_prefix)(); void spu_thread::cpu_task() { + auto end_cpu_task = [&]() + { + // save next PC and current SPU Interrupt status + if (!group && offset >= RAW_SPU_BASE_ADDR) + { + npc = pc | (interrupts_enabled); + } + + if (state & cpu_flag::stop) + { + status |= SPU_STATUS_STOPPED_BY_STOP; + if (group) group->cv.notify_all(); + } + }; + // Get next PC and SPU Interrupt status pc = npc.exchange(0); @@ -508,14 +523,10 @@ void spu_thread::cpu_task() jit_dispatcher[pc / 4](*this, vm::_ptr(offset), nullptr); } - // save next PC and current SPU Interrupt status - if (!group && offset >= RAW_SPU_BASE_ADDR) - { - npc = pc | (interrupts_enabled); - } - // Print some stats LOG_NOTICE(SPU, "Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure); + + end_cpu_task(); return; } @@ -597,11 +608,7 @@ void spu_thread::cpu_task() } } - // save next PC and current SPU Interrupt status - if (!group && offset >= RAW_SPU_BASE_ADDR) - { - npc = pc | (interrupts_enabled); - } + end_cpu_task(); } void spu_thread::cpu_mem() @@ -2060,7 +2067,6 @@ bool spu_thread::stop_and_signal(u32 code) status.atomic_op([code](u32& status) { status = (status & 0xffff) | (code << 16); - status |= SPU_STATUS_STOPPED_BY_STOP; status &= ~SPU_STATUS_RUNNING; }); @@ -2352,10 +2358,29 @@ bool spu_thread::stop_and_signal(u32 code) } } + while (!Emu.IsStopped()) + { + bool stopped = true; + for (auto& thread : group->threads) + { + if (thread && thread.get() != this) + { + if ((thread->status & SPU_STATUS_STOPPED_BY_STOP) == 0) + { + stopped = false; + break; + } + } + } + + if (stopped) break; + + group->cv.wait(group->mutex, 1000); + } + group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; group->exit_status = value; group->join_state |= SPU_TGJSF_GROUP_EXIT; - group->cv.notify_one(); state += cpu_flag::stop; return true; @@ -2374,9 +2399,6 @@ bool spu_thread::stop_and_signal(u32 code) std::lock_guard lock(group->mutex); - status |= SPU_STATUS_STOPPED_BY_STOP; - group->cv.notify_one(); - 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 13202e07c3..1b48c2cb4b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Emu/Memory/vm.h" #include "Emu/System.h" #include "Emu/IdManager.h" @@ -547,7 +547,7 @@ error_code sys_spu_thread_group_yield(u32 id) return CELL_OK; } -error_code sys_spu_thread_group_terminate(u32 id, s32 value) +error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) { sys_spu.warning("sys_spu_thread_group_terminate(id=0x%x, value=0x%x)", id, value); @@ -598,10 +598,33 @@ error_code sys_spu_thread_group_terminate(u32 id, s32 value) } } + while (!ppu.is_stopped()) + { + bool stopped = true; + + for (auto& t : group->threads) + { + if (t) + { + if ((t->status & SPU_STATUS_STOPPED_BY_STOP) == 0) + { + stopped = false; + break; + } + } + } + + if (stopped) break; + + // TODO + group->cv.wait(group->mutex, 1000); + } + + if (ppu.is_stopped()) return 0; + group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; group->exit_status = value; group->join_state |= SPU_TGJSF_TERMINATED; - group->cv.notify_one(); return CELL_OK; } @@ -638,13 +661,8 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause lv2_obj::sleep(ppu); - while ((group->join_state & ~SPU_TGJSF_IS_JOINING) == 0) + while (!ppu.is_stopped()) { - if (ppu.is_stopped()) - { - return 0; - } - bool stopped = true; for (auto& t : group->threads) @@ -659,10 +677,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause } } - if (stopped) - { - break; - } + if (stopped) break; // TODO group->cv.wait(group->mutex, 1000); @@ -674,10 +689,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr cause group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED; // hack } - if (ppu.test_stopped()) - { - return 0; - } + if (ppu.test_stopped()) return 0; switch (join_state & ~SPU_TGJSF_IS_JOINING) { diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index fd96649a48..3d9f8247d8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "sys_event.h" #include "Emu/Cell/SPUThread.h" @@ -300,7 +300,7 @@ error_code sys_spu_thread_group_start(ppu_thread&, u32 id); error_code sys_spu_thread_group_suspend(u32 id); error_code sys_spu_thread_group_resume(u32 id); error_code sys_spu_thread_group_yield(u32 id); -error_code sys_spu_thread_group_terminate(u32 id, s32 value); +error_code sys_spu_thread_group_terminate(ppu_thread&, u32 id, s32 value); error_code sys_spu_thread_group_join(ppu_thread&, u32 id, vm::ptr cause, vm::ptr status); error_code sys_spu_thread_group_set_priority(u32 id, s32 priority); error_code sys_spu_thread_group_get_priority(u32 id, vm::ptr priority);