Attempt to workaround some stop hangs by using MsgWait instead of Wait. change order of dsp / video shutdown. some comments.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2379 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2009-02-22 22:49:42 +00:00
parent a32e29aaa5
commit 68f5cc1873
9 changed files with 89 additions and 44 deletions

View File

@ -133,18 +133,60 @@ void Event::Shutdown()
m_hEvent = 0; m_hEvent = 0;
} }
void Event::Set() void Event::Set()
{ {
SetEvent(m_hEvent); SetEvent(m_hEvent);
} }
void Event::Wait() void Event::Wait()
{ {
WaitForSingleObject(m_hEvent, INFINITE); WaitForSingleObject(m_hEvent, INFINITE);
} }
inline HRESULT MsgWaitForSingleObject(HANDLE handle, DWORD timeout)
{
return MsgWaitForMultipleObjects(1, &handle, FALSE, timeout, 0);
}
void Event::MsgWait()
{
// Adapted from MSDN example http://msdn.microsoft.com/en-us/library/ms687060.aspx
while (true)
{
DWORD result;
MSG msg;
// Read all of the messages in this next loop,
// removing each message as we read it.
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// If it is a quit message, exit.
if (msg.message == WM_QUIT)
return;
// Otherwise, dispatch the message.
DispatchMessage(&msg);
}
// Wait for any message sent or posted to this queue
// or for one of the passed handles be set to signaled.
result = MsgWaitForSingleObject(m_hEvent, INFINITE);
// The result tells us the type of event we have.
if (result == (WAIT_OBJECT_0 + 1))
{
// New messages have arrived.
// Continue to the top of the always while loop to
// dispatch them and resume waiting.
continue;
}
else
{
// result == WAIT_OBJECT_0
// Our event got signaled
return;
}
}
}
///////////////////////////////////// /////////////////////////////////////

View File

@ -98,6 +98,11 @@ public:
void Set(); void Set();
void Wait(); void Wait();
#ifdef _WIN32
void MsgWait();
#else
void MsgWait() {Wait();}
#endif
// ----------------------------------------- // -----------------------------------------
#ifdef SETUP_TIMER_WAITING #ifdef SETUP_TIMER_WAITING

View File

@ -227,7 +227,7 @@ bool Init()
emuThreadGoing.Init(); emuThreadGoing.Init();
// This will execute EmuThread() further down in this file // This will execute EmuThread() further down in this file
g_EmuThread = new Common::Thread(EmuThread, NULL); g_EmuThread = new Common::Thread(EmuThread, NULL);
emuThreadGoing.Wait(); emuThreadGoing.MsgWait();
emuThreadGoing.Shutdown(); emuThreadGoing.Shutdown();
#ifdef SETUP_TIMER_WAITING #ifdef SETUP_TIMER_WAITING
VideoThreadRunning = true; VideoThreadRunning = true;
@ -254,29 +254,27 @@ void Stop()
StopReachedEnd = false; StopReachedEnd = false;
EmuThreadReachedEnd = false; EmuThreadReachedEnd = false;
#endif #endif
Host_SetWaitCursor(true); // hourglass!
Host_SetWaitCursor(true);
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN) if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
return; return;
// Stop the CPU // Stop the CPU
PowerPC::Stop(); PowerPC::Stop();
CCPU::StepOpcode(); // Kick it if it's waiting CCPU::StepOpcode(); // Kick it if it's waiting (code stepping wait loop)
// Wait until the CPU finishes exiting the main run loop
cpuRunloopQuit.Wait(); cpuRunloopQuit.Wait();
cpuRunloopQuit.Shutdown(); cpuRunloopQuit.Shutdown();
// At this point, we must be out of the CPU:s runloop. // At this point, we must be out of the CPU:s runloop.
// Silence audio - stops audio thread. // Stop audio thread.
CPluginManager::GetInstance().GetDSP()->DSP_StopSoundStream(); CPluginManager::GetInstance().GetDSP()->DSP_StopSoundStream();
// If dual core mode, the CPU thread should immediately exit here. // If dual core mode, the CPU thread should immediately exit here.
if (_CoreParameter.bUseDualCore) {
Console::Print("Stop [Main Thread]: Wait for Video Loop...\n"); Console::Print("Stop [Main Thread]: Wait for Video Loop to exit...\n");
// Should be moved inside the plugin.
if (_CoreParameter.bUseDualCore)
CPluginManager::GetInstance().GetVideo()->Video_ExitLoop(); CPluginManager::GetInstance().GetVideo()->Video_ExitLoop();
}
#ifdef SETUP_TIMER_WAITING #ifdef SETUP_TIMER_WAITING
StopUpToVideoDone = true; StopUpToVideoDone = true;
@ -288,15 +286,8 @@ void Stop()
//Console::Print("Stop() will continue\n"); //Console::Print("Stop() will continue\n");
#endif #endif
/* Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest // Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest
of the commands in this function */ // of the commands in this function. We no longer rely on Postmessage. */
/* The quit is to get it out of its message loop. There is no guarantee of when this will occur though.
And since we have no while(GetMessage()) loop we can't wait for this to happen, or say exactly when
the loop has ended */
#ifdef _WIN32
//PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
#endif
// Close the trace file // Close the trace file
Core::StopTrace(); Core::StopTrace();
@ -530,7 +521,6 @@ THREAD_RETURN EmuThread(void *pArg)
cpuThread = new Common::Thread(CpuThread, pArg); cpuThread = new Common::Thread(CpuThread, pArg);
Common::SetCurrentThreadName("Video thread"); Common::SetCurrentThreadName("Video thread");
// I bet that many of our stopping problems come from this loop not properly exiting.
Plugins.GetVideo()->Video_EnterLoop(); Plugins.GetVideo()->Video_EnterLoop();
} }
#ifdef SETUP_TIMER_WAITING #ifdef SETUP_TIMER_WAITING

View File

@ -82,9 +82,10 @@ bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios)
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str()); DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
if (pVolume == NULL) if (pVolume == NULL)
{ {
PanicAlert(bootDrive ?
PanicAlert(bootDrive ? "Drive could not be mounted" : "Disc in %s could not be read - no disc, or not a GC/Wii backup.\n"
"Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO." ); "Please note that original Gamecube and Wii discs cannot be read by most PC DVD drives.":
"Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO.", m_strFilename.c_str());
return false; return false;
} }
m_strName = pVolume->GetName(); m_strName = pVolume->GetName();

View File

@ -208,17 +208,6 @@ void CPluginManager::ShutdownPlugins()
//m_wiimote[i] = NULL; //m_wiimote[i] = NULL;
} }
if (m_video)
{
m_video->Shutdown();
// With this option, this is done on boot instead
#ifndef SETUP_DONT_FREE_PLUGIN_ON_STOP
delete m_video;
m_video = NULL;
#endif
}
if (m_dsp) if (m_dsp)
{ {
m_dsp->Shutdown(); m_dsp->Shutdown();
@ -228,6 +217,16 @@ void CPluginManager::ShutdownPlugins()
m_dsp = NULL; m_dsp = NULL;
#endif #endif
} }
if (m_video)
{
m_video->Shutdown();
// With this option, this is done on boot instead
#ifndef SETUP_DONT_FREE_PLUGIN_ON_STOP
delete m_video;
m_video = NULL;
#endif
}
} }
////////////////////////////////////////////// //////////////////////////////////////////////

View File

@ -72,7 +72,6 @@ EDiscType GetDiscType(IBlobReader& _rReader);
IVolume* CreateVolumeFromFilename(const std::string& _rFilename) IVolume* CreateVolumeFromFilename(const std::string& _rFilename)
{ {
IBlobReader* pReader = CreateBlobReader(_rFilename.c_str()); IBlobReader* pReader = CreateBlobReader(_rFilename.c_str());
if (pReader == NULL) if (pReader == NULL)
return NULL; return NULL;

View File

@ -35,7 +35,7 @@ extern u8* g_pVideoData;
namespace { namespace {
static bool fifoStateRun = false; static volatile bool fifoStateRun = false;
static u8 *videoBuffer; static u8 *videoBuffer;
static Common::Event fifo_exit_event; static Common::Event fifo_exit_event;
// STATE_TO_SAVE // STATE_TO_SAVE
@ -97,11 +97,16 @@ void Video_SendFifoData(u8* _uData, u32 len)
OpcodeDecoder_Run(); OpcodeDecoder_Run();
} }
// Executed from another thread, no the graphics thread!
// Basically, all it does is set a flag so that the loop will eventually exit, then
// waits for the event to be set, which happens when the loop does exit.
// If we look stuck in here, then the video thread is stuck in something and won't exit
// the loop. Switch to the video thread and investigate.
void Fifo_ExitLoop() void Fifo_ExitLoop()
{ {
fifoStateRun = false; fifoStateRun = false;
#ifndef SETUP_TIMER_WAITING #ifndef SETUP_TIMER_WAITING
fifo_exit_event.Wait(); fifo_exit_event.MsgWait();
fifo_exit_event.Shutdown(); fifo_exit_event.Shutdown();
#else #else
//Console::Print("Video: Fifo_ExitLoop: Done:%i\n", fifo_exit_event.DoneWait()); //Console::Print("Video: Fifo_ExitLoop: Done:%i\n", fifo_exit_event.DoneWait());
@ -114,6 +119,7 @@ void Fifo_ExitLoop()
#endif #endif
} }
//
void Fifo_EnterLoop(const SVideoInitialize &video_initialize) void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
{ {
fifoStateRun = true; fifoStateRun = true;

View File

@ -306,8 +306,8 @@ HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const T
m_hWnd = CreateWindow(m_szClassName, title, m_hWnd = CreateWindow(m_szClassName, title,
WS_CHILD, WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
parent, NULL, hInstance, NULL ); parent, NULL, hInstance, NULL);
ShowWindow(m_hWnd, SW_SHOWMAXIMIZED); ShowWindow(m_hWnd, SW_SHOWMAXIMIZED);
} }

View File

@ -134,7 +134,7 @@ FRAGMENTSHADER& GetOrCreateEncodingShader(u32 format)
void Init() void Init()
{ {
glGenFramebuffersEXT( 1, &s_texConvFrameBuffer); glGenFramebuffersEXT(1, &s_texConvFrameBuffer);
glGenRenderbuffersEXT(1, &s_dstRenderBuffer); glGenRenderbuffersEXT(1, &s_dstRenderBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer);
@ -154,6 +154,9 @@ void Shutdown()
glDeleteTextures(1, &s_srcTexture); glDeleteTextures(1, &s_srcTexture);
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer); glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer); glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
s_srcTexture = 0;
s_dstRenderBuffer = 0;
s_texConvFrameBuffer = 0;
} }
void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc, void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc,