From 453a3c48521371dc58cd2457410a3682c5edc78f Mon Sep 17 00:00:00 2001 From: Elad Ashkenazi <18193363+elad335@users.noreply.github.com> Date: Sun, 24 Mar 2024 20:05:10 +0200 Subject: [PATCH] Fixup Savestate Segfault --- rpcs3/Emu/System.cpp | 22 +++++++++++++--------- rpcs3/Emu/System.h | 2 +- rpcs3/headless_application.cpp | 2 +- rpcs3/rpcs3qt/gui_application.cpp | 15 ++++++++++++--- rpcs3/util/serialization_ext.cpp | 8 ++++---- rpcs3/util/serialization_ext.hpp | 2 ++ 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b57b4aba3d..be02da024a 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -43,6 +43,7 @@ #include "../Crypto/unself.h" #include "../Crypto/unzip.h" #include "util/logs.hpp" +#include "util/init_mutex.hpp" #include #include @@ -2970,10 +2971,12 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s *join_thread = make_ptr(new named_thread("Emulation Join Thread"sv, [join_thread, savestate, allow_autoexit, this]() mutable { + fs::pending_file file; + std::shared_ptr init_mtx = std::make_shared(); std::shared_ptr join_ended = std::make_shared(false); atomic_ptr to_ar; - named_thread stop_watchdog("Stop Watchdog"sv, [&to_ar, join_ended, this]() + named_thread stop_watchdog("Stop Watchdog"sv, [&to_ar, init_mtx, join_ended, this]() { const auto closed_sucessfully = std::make_shared>(false); @@ -3008,7 +3011,7 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s if (auto ar_ptr = to_ar.load()) { // Total amount of waiting: about 10s - GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr); + GetCallbacks().on_save_state_progress(closed_sucessfully, ar_ptr, init_mtx); while (thread_ctrl::state() != thread_state::aborting) { @@ -3040,9 +3043,10 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s sys_log.notice("All threads have been stopped."); - fs::pending_file file; std::string path; + static_cast(init_mtx->init()); + while (savestate) { path = get_savestate_file(m_title_id, m_path, 0, 0); @@ -3068,8 +3072,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s break; } - to_ar = stx::make_single(); - to_ar.load()->m_file_handler = make_compressed_serialization_file_handler(file.file); + auto serial_ptr = stx::make_single(); + serial_ptr->m_file_handler = make_compressed_serialization_file_handler(file.file); + to_ar = std::move(serial_ptr); signal_system_cache_can_stay(); break; @@ -3235,6 +3240,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s } } + stop_watchdog = thread_state::finished; + static_cast(init_mtx->reset()); + if (savestate) { auto& ar = *to_ar.load(); @@ -3273,12 +3281,8 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s m_path = path; } } - - ar.set_reading_state(); } - stop_watchdog = thread_state::aborting; - // Log additional debug information - do not do it on the main thread due to the concern of halting UI events if (g_tty && sys_log.notice) diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 51c9ddfab6..8f1767e136 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -64,7 +64,7 @@ struct EmuCallbacks std::function on_ready; std::function on_missing_fw; std::function>, int)> on_emulation_stop_no_response; - std::function>, stx::shared_ptr)> on_save_state_progress; + std::function>, stx::shared_ptr, std::shared_ptr)> on_save_state_progress; std::function enable_disc_eject; std::function enable_disc_insert; std::function)> try_to_quit; // (force_quit, on_exit) Try to close RPCS3 diff --git a/rpcs3/headless_application.cpp b/rpcs3/headless_application.cpp index 6d3692f1e3..eb57704d09 100644 --- a/rpcs3/headless_application.cpp +++ b/rpcs3/headless_application.cpp @@ -148,7 +148,7 @@ void headless_application::InitializeCallbacks() } }; - callbacks.on_save_state_progress = [](std::shared_ptr>, stx::shared_ptr) + callbacks.on_save_state_progress = [](std::shared_ptr>, stx::shared_ptr, std::shared_ptr) { }; diff --git a/rpcs3/rpcs3qt/gui_application.cpp b/rpcs3/rpcs3qt/gui_application.cpp index 16cd7b5a0b..82c3c61296 100644 --- a/rpcs3/rpcs3qt/gui_application.cpp +++ b/rpcs3/rpcs3qt/gui_application.cpp @@ -20,6 +20,7 @@ #include "Emu/Io/Null/null_camera_handler.h" #include "Emu/Io/Null/null_music_handler.h" #include "Emu/vfs_config.h" +#include "util/init_mutex.hpp" #include "Input/raw_mouse_handler.h" #include "trophy_notification_helper.h" #include "save_data_dialog.h" @@ -666,9 +667,9 @@ void gui_application::InitializeCallbacks() }); }; - callbacks.on_save_state_progress = [this](std::shared_ptr> closed_successfully, stx::shared_ptr ar_ptr) + callbacks.on_save_state_progress = [this](std::shared_ptr> closed_successfully, stx::shared_ptr ar_ptr, std::shared_ptr init_mtx) { - Emu.CallFromMainThread([this, closed_successfully, ar_ptr] + Emu.CallFromMainThread([this, closed_successfully, ar_ptr, init_mtx] { const auto half_seconds = std::make_shared(1); @@ -684,8 +685,16 @@ void gui_application::InitializeCallbacks() QTimer* update_timer = new QTimer(pdlg); - connect(update_timer, &QTimer::timeout, [pdlg, ar_ptr, half_seconds, text_base, closed_successfully]() + connect(update_timer, &QTimer::timeout, [pdlg, ar_ptr, half_seconds, text_base, closed_successfully, init_mtx]() { + auto init = static_cast(init_mtx.get())->access(); + + if (!init) + { + pdlg->reject(); + return; + } + *half_seconds += 1; const usz bytes_written = ar_ptr->get_size(); diff --git a/rpcs3/util/serialization_ext.cpp b/rpcs3/util/serialization_ext.cpp index 928cca8dd1..ec47761ef1 100644 --- a/rpcs3/util/serialization_ext.cpp +++ b/rpcs3/util/serialization_ext.cpp @@ -150,12 +150,12 @@ usz uncompressed_serialization_file_handler::get_size(const utils::serial& ar, u { if (ar.is_writing()) { - return m_file->size(); + return *m_file ? m_file->size() : 0; } const usz memory_available = ar.data_offset + ar.data.size(); - if (memory_available >= recommended) + if (memory_available >= recommended || !*m_file) { // Avoid calling size() if possible return memory_available; @@ -756,12 +756,12 @@ usz compressed_serialization_file_handler::get_size(const utils::serial& ar, usz { if (ar.is_writing()) { - return m_file->size(); + return *m_file ? m_file->size() : 0; } const usz memory_available = ar.data_offset + ar.data.size(); - if (memory_available >= recommended) + if (memory_available >= recommended || !*m_file) { // Avoid calling size() if possible return memory_available; diff --git a/rpcs3/util/serialization_ext.hpp b/rpcs3/util/serialization_ext.hpp index 72a96b809f..bfa3c37cd6 100644 --- a/rpcs3/util/serialization_ext.hpp +++ b/rpcs3/util/serialization_ext.hpp @@ -30,6 +30,7 @@ struct uncompressed_serialization_file_handler : utils::serialization_file_handl } uncompressed_serialization_file_handler(const uncompressed_serialization_file_handler&) = delete; + uncompressed_serialization_file_handler& operator=(const uncompressed_serialization_file_handler&) = delete; // Handle file read and write requests bool handle_file_op(utils::serial& ar, usz pos, usz size, const void* data) override; @@ -68,6 +69,7 @@ struct compressed_serialization_file_handler : utils::serialization_file_handler } compressed_serialization_file_handler(const compressed_serialization_file_handler&) = delete; + compressed_serialization_file_handler& operator=(const compressed_serialization_file_handler&) = delete; // Handle file read and write requests bool handle_file_op(utils::serial& ar, usz pos, usz size, const void* data) override;