Fixed a small threading issue introduced by r6933 causing savestates to always freeze, thanks to artart78 for pinpointing the issue.

Properly pause the core when saving/loading savestates, previously we used PowerPC::Pause() and Start() which only update the state but doesn't properly set m_StepEvent and caused random hangs.
Fixed hang when creating a savestate while the game was paused or in Frame Advance mode, now the thing works (just remember to press play duh).

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6992 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
sl1nk3.s
2011-01-30 21:20:33 +00:00
parent 4e74a58c2a
commit 7a4c203f69
5 changed files with 39 additions and 32 deletions

View File

@ -163,7 +163,7 @@ bool isRunning()
bool IsRunningInCurrentThread() bool IsRunningInCurrentThread()
{ {
return isRunning() && ((cpuThread.joinable()) || cpuThread.get_id() == std::this_thread::get_id()); return isRunning() && ((!cpuThread.joinable()) || cpuThread.get_id() == std::this_thread::get_id());
} }
// This is called from the GUI thread. See the booting call schedule in // This is called from the GUI thread. See the booting call schedule in

View File

@ -68,7 +68,7 @@ u64 fakeDecStartTicks;
u64 fakeTBStartValue; u64 fakeTBStartValue;
u64 fakeTBStartTicks; u64 fakeTBStartTicks;
Common::CriticalSection externalEventSection; static Common::CriticalSection externalEventSection;
void (*advanceCallback)(int cyclesExecuted) = NULL; void (*advanceCallback)(int cyclesExecuted) = NULL;

View File

@ -27,7 +27,7 @@
#include "HW/Wiimote.h" #include "HW/Wiimote.h"
#include "HW/DSP.h" #include "HW/DSP.h"
#include "HW/HW.h" #include "HW/HW.h"
#include "PowerPC/PowerPC.h" #include "HW/CPU.h"
#include "PowerPC/JitCommon/JitBase.h" #include "PowerPC/JitCommon/JitBase.h"
#include "PluginManager.h" #include "PluginManager.h"
@ -93,6 +93,7 @@ void DoState(PointerWrap &p)
if (Core::g_CoreStartupParameter.bWii) if (Core::g_CoreStartupParameter.bWii)
Wiimote::DoState(p.GetPPtr(), p.GetMode()); Wiimote::DoState(p.GetPPtr(), p.GetMode());
PowerPC::DoState(p); PowerPC::DoState(p);
HW::DoState(p); HW::DoState(p);
CoreTiming::DoState(p); CoreTiming::DoState(p);
@ -170,6 +171,9 @@ void CompressAndDumpState(saveStruct* saveArg)
delete saveArg; delete saveArg;
// For easy debugging
Common::SetCurrentThreadName("SaveState thread");
// Moving to last overwritten save-state // Moving to last overwritten save-state
if (File::Exists(cur_filename.c_str())) if (File::Exists(cur_filename.c_str()))
{ {
@ -233,8 +237,8 @@ void CompressAndDumpState(saveStruct* saveArg)
void SaveStateCallback(u64 userdata, int cyclesLate) void SaveStateCallback(u64 userdata, int cyclesLate)
{ {
// Stop the clock while we save the state // Pause the core while we save the state
PowerPC::Pause(); CCPU::EnableStepping(true);
// Wait for the other threaded sub-systems to stop too // Wait for the other threaded sub-systems to stop too
SLEEP(100); SLEEP(100);
@ -264,16 +268,16 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
saveThread = std::thread(CompressAndDumpState, saveData); saveThread = std::thread(CompressAndDumpState, saveData);
// Resume the clock // Resume the core and disable stepping
PowerPC::Start(); CCPU::EnableStepping(false);
} }
void LoadStateCallback(u64 userdata, int cyclesLate) void LoadStateCallback(u64 userdata, int cyclesLate)
{ {
bool bCompressedState; bool bCompressedState;
// Stop the clock while we load the state // Stop the core while we load the state
PowerPC::Pause(); CCPU::EnableStepping(true);
// Wait for the other threaded sub-systems to stop too // Wait for the other threaded sub-systems to stop too
SLEEP(100); SLEEP(100);
@ -295,7 +299,7 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
{ {
Core::DisplayMessage("State not found", 2000); Core::DisplayMessage("State not found", 2000);
// Resume the clock // Resume the clock
PowerPC::Start(); CCPU::EnableStepping(false);
return; return;
} }
@ -314,7 +318,7 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
fclose(f); fclose(f);
// Resume the clock // Resume the clock
PowerPC::Start(); CCPU::EnableStepping(false);
return; return;
} }
@ -330,7 +334,7 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
{ {
PanicAlertT("Error allocating buffer"); PanicAlertT("Error allocating buffer");
// Resume the clock // Resume the clock
PowerPC::Start(); CCPU::EnableStepping(false);
return; return;
} }
while (true) while (true)
@ -351,7 +355,7 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
fclose(f); fclose(f);
delete[] buffer; delete[] buffer;
// Resume the clock // Resume the clock
PowerPC::Start(); CCPU::EnableStepping(false);
return; return;
} }
@ -388,7 +392,7 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
state_op_in_progress = false; state_op_in_progress = false;
// Resume the clock // Resume the clock
PowerPC::Start(); CCPU::EnableStepping(false);
} }
void VerifyStateCallback(u64 userdata, int cyclesLate) void VerifyStateCallback(u64 userdata, int cyclesLate)

View File

@ -34,7 +34,6 @@ namespace
static volatile bool fifoStateRun = false; static volatile bool fifoStateRun = false;
static volatile bool EmuRunning = false; static volatile bool EmuRunning = false;
static u8 *videoBuffer; static u8 *videoBuffer;
static Common::EventEx fifo_run_event;
// STATE_TO_SAVE // STATE_TO_SAVE
static int size = 0; static int size = 0;
} // namespace } // namespace
@ -55,14 +54,12 @@ void Fifo_DoState(PointerWrap &p)
void Fifo_Init() void Fifo_Init()
{ {
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE); videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
fifo_run_event.Init();
fifoStateRun = false; fifoStateRun = false;
} }
void Fifo_Shutdown() void Fifo_Shutdown()
{ {
if (fifoStateRun) PanicAlert("Fifo shutting down while active"); if (fifoStateRun) PanicAlert("Fifo shutting down while active");
fifo_run_event.Shutdown();
FreeMemoryPages(videoBuffer, FIFO_SIZE); FreeMemoryPages(videoBuffer, FIFO_SIZE);
} }
@ -89,6 +86,7 @@ void Fifo_SetRendering(bool enabled)
void Fifo_ExitLoop() void Fifo_ExitLoop()
{ {
Fifo_ExitLoopNonBlocking(); Fifo_ExitLoopNonBlocking();
EmuRunning = true;
} }
// May be executed from any thread, even the graphics thread. // May be executed from any thread, even the graphics thread.
@ -100,14 +98,12 @@ void Fifo_ExitLoopNonBlocking()
CommandProcessor::SetFifoIdleFromVideoPlugin(); CommandProcessor::SetFifoIdleFromVideoPlugin();
// Terminate GPU thread loop // Terminate GPU thread loop
fifoStateRun = false; fifoStateRun = false;
fifo_run_event.Set(); EmuRunning = true;
} }
void Fifo_RunLoop(bool run) void Fifo_RunLoop(bool run)
{ {
EmuRunning = run; EmuRunning = run;
if (run)
fifo_run_event.Set();
} }
// Description: Fifo_EnterLoop() sends data through this function. // Description: Fifo_EnterLoop() sends data through this function.
@ -164,8 +160,8 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
if (!fifoStateRun) break; if (!fifoStateRun) break;
CommandProcessor::FifoCriticalEnter(); CommandProcessor::FifoCriticalEnter();
// Create pointer to video data and send it to the VideoPlugin // Create pointer to video data and send it to the VideoPlugin
u32 readPtr = _fifo.CPReadPointer; u32 readPtr = _fifo.CPReadPointer;
u8 *uData = video_initialize.pGetMemoryPointer(readPtr); u8 *uData = video_initialize.pGetMemoryPointer(readPtr);
@ -192,21 +188,27 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
CommandProcessor::FifoCriticalLeave(); CommandProcessor::FifoCriticalLeave();
// Those two are pretty important and must be called in the FIFO Loop. // This call is pretty important in DualCore mode and must be called in the FIFO Loop.
// If we don't, s_swapRequested (OGL only) or s_efbAccessRequested won't be set to false // If we don't, s_swapRequested or s_efbAccessRequested won't be set to false
// leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down. // leading the CPU thread to wait in Video_BeginField or Video_AccessEFB thus slowing things down.
VideoFifo_CheckAsyncRequest(); VideoFifo_CheckAsyncRequest();
} }
CommandProcessor::isFifoBusy = false; CommandProcessor::isFifoBusy = false;
CommandProcessor::SetFifoIdleFromVideoPlugin(); CommandProcessor::SetFifoIdleFromVideoPlugin();
if (EmuRunning) if (EmuRunning)
Common::YieldCPU(); Common::YieldCPU();
else else
fifo_run_event.MsgWait(); {
// While the emu is paused, we still handle async request such as Savestates then sleep.
while (!EmuRunning)
{
video_initialize.pPeekMessages();
VideoFifo_CheckAsyncRequest();
Common::SleepCurrentThread(10);
}
}
} }
} }

View File

@ -170,7 +170,8 @@ static volatile struct
int mode; int mode;
} s_doStateArgs; } s_doStateArgs;
// Run from the GPU thread on X11, CPU thread on the rest // Depending on the threading mode (DC/SC) this can be called
// from either the GPU thread or the CPU thread
static void check_DoState() { static void check_DoState() {
if (Common::AtomicLoadAcquire(s_doStateRequested)) if (Common::AtomicLoadAcquire(s_doStateRequested))
{ {
@ -194,7 +195,7 @@ static void check_DoState() {
} }
} }
// Run from the CPU thread // Run from the GUI thread
void DoState(unsigned char **ptr, int mode) void DoState(unsigned char **ptr, int mode)
{ {
s_doStateArgs.ptr = ptr; s_doStateArgs.ptr = ptr;
@ -207,7 +208,7 @@ void DoState(unsigned char **ptr, int mode)
Common::YieldCPU(); Common::YieldCPU();
} }
else else
check_DoState(); check_DoState();
} }
void VideoFifo_CheckAsyncRequest() void VideoFifo_CheckAsyncRequest()