From 2197d9698960201de02cd23657fcd02899c56ea1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 27 Dec 2012 11:28:12 -0800 Subject: [PATCH] Run save state operations at next Advance(). Should take some question marks out of things. --- Core/HLE/HLE.h | 4 -- Core/HLE/sceKernel.cpp | 2 + Core/SaveState.cpp | 146 ++++++++++++++++++++++++++++++++++------- Core/SaveState.h | 24 ++++--- 4 files changed, 139 insertions(+), 37 deletions(-) diff --git a/Core/HLE/HLE.h b/Core/HLE/HLE.h index fb0eefa1be..09d5fc75cd 100644 --- a/Core/HLE/HLE.h +++ b/Core/HLE/HLE.h @@ -94,7 +94,3 @@ void WriteSyscall(const char *module, u32 nib, u32 address); void CallSyscall(u32 op); void ResolveSyscall(const char *moduleName, u32 nib, u32 address); -// Need to be able to save entire kernel state -int GetStateSize(); -void SaveState(u8 *ptr); -void LoadState(const u8 *ptr); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index da528027eb..20f3af0997 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -24,6 +24,7 @@ #include "../FileSystems/MetaFileSystem.h" #include "../PSPLoaders.h" #include "../../Core/CoreTiming.h" +#include "../../Core/SaveState.h" #include "../../Core/System.h" #include "../../GPU/GPUInterface.h" #include "../../GPU/GPUState.h" @@ -77,6 +78,7 @@ void __KernelInit() return; } + SaveState::Init(); __KernelMemoryInit(); __KernelThreadingInit(); __KernelMutexInit(); diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index bbf0e2328d..43d181bb9b 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -15,32 +15,130 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "../Common/StdMutex.h" +#include + #include "SaveState.h" -#include "MemMap.h" +#include "CoreTiming.h" #include "HLE/sceKernel.h" +#include "MemMap.h" -// TODO: Need a way to schedule via CoreTiming and actually run then. - -bool SaveState::Load(std::string &filename) +namespace SaveState { - SaveState state; - return CChunkFileReader::Load(filename, REVISION, state); + struct SaveStart + { + void DoState(PointerWrap &p); + }; + + enum OperationType + { + SAVESTATE_SAVE, + SAVESTATE_LOAD, + SAVESTATE_VERIFY, + }; + + struct Operation + { + Operation(OperationType t, std::string &f, Callback cb) + : type(t), filename(f), callback(cb) + { + } + + OperationType type; + std::string filename; + Callback callback; + }; + + static int timer; + static std::vector pending; + static std::recursive_mutex mutex; + + // This is where the magic happens. + void SaveStart::DoState(PointerWrap &p) + { + // This save state even saves its own state. + p.Do(timer); + p.DoMarker("SaveState"); + + Memory::DoState(p); + __KernelDoState(p); + } + + void Enqueue(SaveState::Operation op) + { + std::lock_guard guard(mutex); + pending.push_back(op); + + // Don't actually run it until next CoreTiming::Advance(). + // It's possible there might be a duplicate but it won't hurt us. + // TODO: If paused, just run, don't wait? + CoreTiming::ScheduleEvent_Threadsafe(0, timer); + } + + void Load(std::string &filename, Callback callback) + { + Enqueue(Operation(SAVESTATE_LOAD, filename, callback)); + } + + void Save(std::string &filename, Callback callback) + { + Enqueue(Operation(SAVESTATE_SAVE, filename, callback)); + } + + void Verify(Callback callback) + { + Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback)); + } + + std::vector Flush() + { + std::lock_guard guard(mutex); + std::vector copy = pending; + pending.clear(); + + return copy; + } + + void Process(u64 userdata, int cyclesLate) + { + std::vector operations = Flush(); + SaveStart state; + + for (size_t i = 0, n = operations.size(); i < n; ++i) + { + Operation &op = operations[i]; + bool result; + + switch (op.type) + { + case SAVESTATE_LOAD: + INFO_LOG(COMMON, "Loading state from %s", op.filename.c_str()); + result = CChunkFileReader::Load(op.filename, REVISION, state); + break; + + case SAVESTATE_SAVE: + INFO_LOG(COMMON, "Saving state to %s", op.filename.c_str()); + result = CChunkFileReader::Save(op.filename, REVISION, state); + break; + + case SAVESTATE_VERIFY: + INFO_LOG(COMMON, "Verifying save state system"); + result = CChunkFileReader::Verify(state); + break; + + default: + ERROR_LOG(COMMON, "Savestate failure: unknown operation type %d", op.type); + result = false; + break; + } + + if (op.callback != NULL) + op.callback(result); + } + } + + void Init() + { + timer = CoreTiming::RegisterEvent("SaveState", Process); + } } - -bool SaveState::Save(std::string &filename) -{ - SaveState state; - return CChunkFileReader::Save(filename, REVISION, state); -} - -bool SaveState::Verify() -{ - SaveState state; - return CChunkFileReader::Verify(state); -} - -void SaveState::DoState(PointerWrap &p) -{ - Memory::DoState(p); - __KernelDoState(p); -} \ No newline at end of file diff --git a/Core/SaveState.h b/Core/SaveState.h index f0edfcf921..411ad2f88c 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -16,18 +16,24 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "../Common/ChunkFile.h" +#include -struct SaveState +namespace SaveState { + typedef void (*Callback)(bool status); + // TODO: Better place for this? - static const int REVISION = 1; + const int REVISION = 1; - // Load the specified file into the current state. - static bool Load(std::string &filename); - // Save the current state to the specified file. - static bool Save(std::string &filename); - // For testing / automated tests. Runs a save state verification pass. - static bool Verify(); + void Init(); - void DoState(PointerWrap &p); + // Load the specified file into the current state (async.) + // Warning: callback will be called on a different thread. + void Load(std::string &filename, Callback callback = NULL); + // Save the current state to the specified file (async.) + // Warning: callback will be called on a different thread. + void Save(std::string &filename, Callback callback = NULL); + // For testing / automated tests. Runs a save state verification pass (async.) + // Warning: callback will be called on a different thread. + void Verify(Callback callback = NULL); }; \ No newline at end of file