mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 05:40:01 -06:00
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:
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
Reference in New Issue
Block a user