1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Savestates: Warn on invalid SPU save state

This commit is contained in:
Elad Ashkenazi 2024-05-14 10:34:30 +03:00
parent 32e01b5f1a
commit 6d8575d0d0
4 changed files with 39 additions and 6 deletions

View File

@ -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<std::pair<std::shared_ptr<named_thread<spu_thread>>, u32>>* out_list)
{
if (out_list)
{
out_list->clear();
}
auto get_spus = [old_counter = u64{umax}, spu_list = std::vector<std::shared_ptr<named_thread<spu_thread>>>()](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;
}

View File

@ -1813,7 +1813,10 @@ void spu_thread::cpu_task()
spu_runtime::g_gateway(*this, _ptr<u8>(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);

View File

@ -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<std::pair<std::shared_ptr<named_thread<spu_thread>>, 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<std::pair<std::shared_ptr<named_thread<spu_thread>>, 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<std::shared_ptr<void>> join_thread = std::make_shared<std::shared_ptr<void>>();
*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();

View File

@ -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 <typename T>
class named_thread;
enum class system_state : u32
{
stopped,
@ -351,6 +356,7 @@ private:
struct savestate_stage
{
bool prepared = false;
std::vector<std::pair<std::shared_ptr<named_thread<spu_thread>>, u32>> paused_spus;
};
public: