Merge pull request #10435 from AdmiralCurtiss/savestate-crash

Core/State: Add some multithreading protections.
This commit is contained in:
JMC47
2022-02-11 06:28:46 -05:00
committed by GitHub

View File

@ -64,12 +64,13 @@ static AfterLoadCallbackFunc s_on_after_load_callback;
// Temporary undo state buffer // Temporary undo state buffer
static std::vector<u8> g_undo_load_buffer; static std::vector<u8> g_undo_load_buffer;
static std::vector<u8> g_current_buffer; static std::vector<u8> g_current_buffer;
static bool s_load_or_save_in_progress; static std::mutex s_load_or_save_in_progress_mutex;
static std::mutex g_cs_undo_load_buffer; static std::mutex g_cs_undo_load_buffer;
static std::mutex g_cs_current_buffer; static std::mutex g_cs_current_buffer;
static Common::Event g_compressAndDumpStateSyncEvent; static Common::Event g_compressAndDumpStateSyncEvent;
static std::recursive_mutex g_save_thread_mutex;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
@ -403,11 +404,10 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args)
void SaveAs(const std::string& filename, bool wait) void SaveAs(const std::string& filename, bool wait)
{ {
if (s_load_or_save_in_progress) std::unique_lock lk(s_load_or_save_in_progress_mutex, std::try_to_lock);
if (!lk)
return; return;
s_load_or_save_in_progress = true;
Core::RunOnCPUThread( Core::RunOnCPUThread(
[&] { [&] {
// Measure the size of the buffer. // Measure the size of the buffer.
@ -435,8 +435,12 @@ void SaveAs(const std::string& filename, bool wait)
save_args.filename = filename; save_args.filename = filename;
save_args.wait = wait; save_args.wait = wait;
Flush(); {
g_save_thread = std::thread(CompressAndDumpState, save_args); std::lock_guard lk(g_save_thread_mutex);
Flush();
g_save_thread = std::thread(CompressAndDumpState, save_args);
}
g_compressAndDumpStateSyncEvent.Wait(); g_compressAndDumpStateSyncEvent.Wait();
} }
else else
@ -446,8 +450,6 @@ void SaveAs(const std::string& filename, bool wait)
} }
}, },
true); true);
s_load_or_save_in_progress = false;
} }
bool ReadHeader(const std::string& filename, StateHeader& header) bool ReadHeader(const std::string& filename, StateHeader& header)
@ -550,17 +552,18 @@ static void LoadFileStateData(const std::string& filename, std::vector<u8>& ret_
void LoadAs(const std::string& filename) void LoadAs(const std::string& filename)
{ {
if (!Core::IsRunning() || s_load_or_save_in_progress) if (!Core::IsRunning())
{
return; return;
}
else if (NetPlay::IsNetPlayRunning()) if (NetPlay::IsNetPlayRunning())
{ {
OSD::AddMessage("Loading savestates is disabled in Netplay to prevent desyncs"); OSD::AddMessage("Loading savestates is disabled in Netplay to prevent desyncs");
return; return;
} }
s_load_or_save_in_progress = true; std::unique_lock lk(s_load_or_save_in_progress_mutex, std::try_to_lock);
if (!lk)
return;
Core::RunOnCPUThread( Core::RunOnCPUThread(
[&] { [&] {
@ -617,8 +620,6 @@ void LoadAs(const std::string& filename)
s_on_after_load_callback(); s_on_after_load_callback();
}, },
true); true);
s_load_or_save_in_progress = false;
} }
void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback) void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback)
@ -699,6 +700,8 @@ void SaveFirstSaved()
void Flush() void Flush()
{ {
std::lock_guard lk(g_save_thread_mutex);
// If already saving state, wait for it to finish // If already saving state, wait for it to finish
if (g_save_thread.joinable()) if (g_save_thread.joinable())
g_save_thread.join(); g_save_thread.join();