diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 7230fcb403..195f4da044 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1459,8 +1459,13 @@ u32 CPUDisAsm::DisAsmBranchTarget(s32 /*imm*/) return 0; } -extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock) +extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock, std::vector>, u32>>* out_list) { + if (out_list) + { + out_list->clear(); + } + auto get_spus = [old_counter = u64{umax}, spu_list = std::vector>>()](bool can_collect, bool force_collect) mutable { const u64 new_counter = cpu_thread::g_threads_created + cpu_thread::g_threads_deleted; @@ -1634,6 +1639,14 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve continue; } + if (out_list) + { + for (auto& spu : *spu_list) + { + out_list->emplace_back(spu, spu->pc); + } + } + return true; } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index e52017a88c..43e22f97e3 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1813,7 +1813,10 @@ void spu_thread::cpu_task() spu_runtime::g_gateway(*this, _ptr(0), nullptr); } - unsavable = false; + if (unsavable && is_stopped(state - cpu_flag::stop)) + { + spu_log.warning("Aborting unsaveable state"); + } // Print some stats (!group || group->stop_count < 5 ? spu_log.notice : spu_log.trace)("Stats: Block Weight: %u (Retreats: %u);", block_counter, block_failure); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index d79a4a34cb..7d90623729 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -2872,7 +2872,7 @@ void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op, bool savesta } extern bool check_if_vdec_contexts_exist(); -extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock = false); +extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool revert_lock = false, std::vector>, u32>>* out_list = nullptr); void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_stage) { @@ -2894,7 +2894,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s *pause_thread = make_ptr(new named_thread("Savestate Prepare Thread"sv, [pause_thread, allow_autoexit, this]() mutable { - if (!try_lock_spu_threads_in_a_state_compatible_with_savestates()) + std::vector>, u32>> paused_spus; + + if (!try_lock_spu_threads_in_a_state_compatible_with_savestates(false, &paused_spus)) { sys_log.error("Failed to savestate: failed to lock SPU threads execution."); @@ -2962,10 +2964,11 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s return; } - CallFromMainThread([allow_autoexit, this]() + CallFromMainThread([allow_autoexit, this, paused_spus]() { savestate_stage stage{}; stage.prepared = true; + stage.paused_spus = paused_spus; Kill(allow_autoexit, true, &stage); }); @@ -3071,7 +3074,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s // There is no race condition because it is only accessed by the same thread std::shared_ptr> join_thread = std::make_shared>(); - *join_thread = make_ptr(new named_thread("Emulation Join Thread"sv, [join_thread, savestate, allow_autoexit, this]() mutable + *join_thread = make_ptr(new named_thread("Emulation Join Thread"sv, [join_thread, savestate, allow_autoexit, save_stage = save_stage ? *save_stage : savestate_stage{}, this]() mutable { fs::pending_file file; @@ -3142,6 +3145,14 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s } } + for (const auto& spu : save_stage.paused_spus) + { + if (spu.first->pc != spu.second) + { + sys_log.error("SPU thread continued after being paused. (old_pc=0x%x, pc=0x%x, unsavable=%d)", spu.second, spu.first->pc, spu.first->unsavable); + + } + } // Save it first for maximum timing accuracy const u64 timestamp = get_timebased_time(); const u64 start_time = get_system_time(); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index d6f8e59b8f..27292c8f98 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -19,6 +19,11 @@ void init_fxo_for_exec(utils::serial*, bool); enum class localized_string_id; enum class video_renderer; +class spu_thread; + +template +class named_thread; + enum class system_state : u32 { stopped, @@ -351,6 +356,7 @@ private: struct savestate_stage { bool prepared = false; + std::vector>, u32>> paused_spus; }; public: