State: Use RunOnCPUThread to invoke save state handlers

This ensures that the emulated state is only touched by the CPU thread
This commit is contained in:
Stenzek 2019-06-29 18:25:04 +10:00
parent df45e714a3
commit a25a4e0708
1 changed files with 105 additions and 97 deletions

View File

@ -204,27 +204,31 @@ void LoadFromBuffer(std::vector<u8>& buffer)
return; return;
} }
Core::RunAsCPUThread([&] { Core::RunOnCPUThread(
u8* ptr = &buffer[0]; [&] {
PointerWrap p(&ptr, PointerWrap::MODE_READ); u8* ptr = &buffer[0];
DoState(p); PointerWrap p(&ptr, PointerWrap::MODE_READ);
}); DoState(p);
},
true);
} }
void SaveToBuffer(std::vector<u8>& buffer) void SaveToBuffer(std::vector<u8>& buffer)
{ {
Core::RunAsCPUThread([&] { Core::RunOnCPUThread(
u8* ptr = nullptr; [&] {
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); u8* ptr = nullptr;
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
DoState(p); DoState(p);
const size_t buffer_size = reinterpret_cast<size_t>(ptr); const size_t buffer_size = reinterpret_cast<size_t>(ptr);
buffer.resize(buffer_size); buffer.resize(buffer_size);
ptr = &buffer[0]; ptr = &buffer[0];
p.SetMode(PointerWrap::MODE_WRITE); p.SetMode(PointerWrap::MODE_WRITE);
DoState(p); DoState(p);
}); },
true);
} }
// return state number not in map // return state number not in map
@ -381,42 +385,44 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args)
void SaveAs(const std::string& filename, bool wait) void SaveAs(const std::string& filename, bool wait)
{ {
Core::RunAsCPUThread([&] { Core::RunOnCPUThread(
// Measure the size of the buffer. [&] {
u8* ptr = nullptr; // Measure the size of the buffer.
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); u8* ptr = nullptr;
DoState(p); PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
const size_t buffer_size = reinterpret_cast<size_t>(ptr); DoState(p);
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
// Then actually do the write. // Then actually do the write.
{ {
std::lock_guard<std::mutex> lk(g_cs_current_buffer); std::lock_guard<std::mutex> lk(g_cs_current_buffer);
g_current_buffer.resize(buffer_size); g_current_buffer.resize(buffer_size);
ptr = &g_current_buffer[0]; ptr = &g_current_buffer[0];
p.SetMode(PointerWrap::MODE_WRITE); p.SetMode(PointerWrap::MODE_WRITE);
DoState(p); DoState(p);
} }
if (p.GetMode() == PointerWrap::MODE_WRITE) if (p.GetMode() == PointerWrap::MODE_WRITE)
{ {
Core::DisplayMessage("Saving State...", 1000); Core::DisplayMessage("Saving State...", 1000);
CompressAndDumpState_args save_args; CompressAndDumpState_args save_args;
save_args.buffer_vector = &g_current_buffer; save_args.buffer_vector = &g_current_buffer;
save_args.buffer_mutex = &g_cs_current_buffer; save_args.buffer_mutex = &g_cs_current_buffer;
save_args.filename = filename; save_args.filename = filename;
save_args.wait = wait; save_args.wait = wait;
Flush(); Flush();
g_save_thread = std::thread(CompressAndDumpState, save_args); g_save_thread = std::thread(CompressAndDumpState, save_args);
g_compressAndDumpStateSyncEvent.Wait(); g_compressAndDumpStateSyncEvent.Wait();
} }
else else
{ {
// someone aborted the save by changing the mode? // someone aborted the save by changing the mode?
Core::DisplayMessage("Unable to save: Internal DoState Error", 4000); Core::DisplayMessage("Unable to save: Internal DoState Error", 4000);
} }
}); },
true);
} }
bool ReadHeader(const std::string& filename, StateHeader& header) bool ReadHeader(const std::string& filename, StateHeader& header)
@ -525,64 +531,66 @@ void LoadAs(const std::string& filename)
return; return;
} }
Core::RunAsCPUThread([&] { Core::RunOnCPUThread(
g_loadDepth++; [&] {
g_loadDepth++;
// Save temp buffer for undo load state // Save temp buffer for undo load state
if (!Movie::IsJustStartingRecordingInputFromSaveState()) if (!Movie::IsJustStartingRecordingInputFromSaveState())
{ {
std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer); std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
SaveToBuffer(g_undo_load_buffer); SaveToBuffer(g_undo_load_buffer);
if (Movie::IsMovieActive()) if (Movie::IsMovieActive())
Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm")) else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"))
File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"); File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
} }
bool loaded = false; bool loaded = false;
bool loadedSuccessfully = false; bool loadedSuccessfully = false;
// brackets here are so buffer gets freed ASAP // brackets here are so buffer gets freed ASAP
{ {
std::vector<u8> buffer; std::vector<u8> buffer;
LoadFileStateData(filename, buffer); LoadFileStateData(filename, buffer);
if (!buffer.empty()) if (!buffer.empty())
{ {
u8* ptr = &buffer[0]; u8* ptr = &buffer[0];
PointerWrap p(&ptr, PointerWrap::MODE_READ); PointerWrap p(&ptr, PointerWrap::MODE_READ);
DoState(p); DoState(p);
loaded = true; loaded = true;
loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ); loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ);
} }
} }
if (loaded) if (loaded)
{ {
if (loadedSuccessfully) if (loadedSuccessfully)
{ {
Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000); Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000);
if (File::Exists(filename + ".dtm")) if (File::Exists(filename + ".dtm"))
Movie::LoadInput(filename + ".dtm"); Movie::LoadInput(filename + ".dtm");
else if (!Movie::IsJustStartingRecordingInputFromSaveState() && else if (!Movie::IsJustStartingRecordingInputFromSaveState() &&
!Movie::IsJustStartingPlayingInputFromSaveState()) !Movie::IsJustStartingPlayingInputFromSaveState())
Movie::EndPlayInput(false); Movie::EndPlayInput(false);
} }
else else
{ {
Core::DisplayMessage("The savestate could not be loaded", OSD::Duration::NORMAL); Core::DisplayMessage("The savestate could not be loaded", OSD::Duration::NORMAL);
// since we could be in an inconsistent state now (and might crash or whatever), undo. // since we could be in an inconsistent state now (and might crash or whatever), undo.
if (g_loadDepth < 2) if (g_loadDepth < 2)
UndoLoadState(); UndoLoadState();
} }
} }
if (s_on_after_load_callback) if (s_on_after_load_callback)
s_on_after_load_callback(); s_on_after_load_callback();
g_loadDepth--; g_loadDepth--;
}); },
true);
} }
void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback) void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback)