Core Stop and Start: Added alternative separate thread timer/loop based waiting, instead of same thread loop waiting. You can try it with the SETUP_TIMER_WAITING option in Setup.h.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2375 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson
2009-02-22 21:16:12 +00:00
parent 769160dfbd
commit 927815bc9b
16 changed files with 367 additions and 31 deletions

View File

@ -49,6 +49,15 @@
// Build with playback rerecording options
//#define SETUP_AVOID_OPENGL_SCREEN_MESSAGE_HANG
// Use a timer to wait for threads for stop instead of WaitForEternity()
/* I tried that this worked with these options
SETUP_FREE_VIDEO_PLUGIN_ON_BOOT
SETUP_DONT_FREE_PLUGIN_ON_STOP
then the Confirm on Close message box doesn't hang, and we have a controlled Shutdown process
without any hanged threads. The downside is a few error messages in the ShutDown() of the
OpenGL plugin, so I still need FreeLibrary() to clean it, even with this option. */
//#define SETUP_TIMER_WAITING
// Build with playback rerecording options
//#define RERECORDING

View File

@ -15,7 +15,16 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "Setup.h"
#include "Thread.h"
// -----------------------------------------
#ifdef SETUP_TIMER_WAITING
// -----------------
#include <windows.h>
#include "ConsoleWindow.h"
EventCallBack FunctionPointer[10];
#endif
// ------------------------
#define THREAD_DEBUG 1
@ -99,9 +108,18 @@ void Thread::SetCurrentThreadAffinity(int mask)
}
//////////////////////////////////////////////////////////////////////////////////////////
// Regular same thread loop based waiting
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Event::Event()
{
m_hEvent = 0;
#ifdef SETUP_TIMER_WAITING
DoneWaiting = false;
StartWait = false;
hTimer = NULL;
hTimerQueue = NULL;
#endif
}
void Event::Init()
@ -115,22 +133,125 @@ void Event::Shutdown()
m_hEvent = 0;
}
void Event::Set()
{
SetEvent(m_hEvent);
}
void Event::Wait()
{
WaitForSingleObject(m_hEvent, INFINITE);
}
/////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
/* Separate thread timer based waiting, instead of same thread loop waiting. The downside with this
is that it's less convenient to use because we can't stall any threads with a loop. The positive
is that we don't cause these incredibly annoying WaitForEternity() hangings. */
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
#ifdef SETUP_TIMER_WAITING
/* I could not figure out how to place this in the class to, CreateTimerQueueTimer() would complain
about some kind of type casting, anyone have any ideas about how to do it? */
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
if (lpParam == NULL)
{
Console::Print("TimerRoutine lpParam is NULL\n");
}
else
{
// lpParam points to the argument; in this case it is an int
//Console::Print("Timer[%i] will call back\n", *(int*)lpParam);
}
// Call back
int Id = *(int*)lpParam;
if (FunctionPointer[Id]) FunctionPointer[Id]();
}
// Create a timer that will call back to the calling function
bool Event::TimerWait(EventCallBack WaitCB, int _Id, bool OptCondition)
{
Id = _Id;
//Console::Print("TimerWait[%i]: %i %i %i\n", Id, StartWait, DoneWaiting, OptCondition);
FunctionPointer[Id] = WaitCB;
// This means we are done waiting, so we wont call back again, and we also reset the variables for this Event
if (DoneWaiting && OptCondition)
{
StartWait = false;
DoneWaiting = false;
FunctionPointer[Id] = NULL;
// Delete all timers in the timer queue.
if (!DeleteTimerQueue(hTimerQueue))
Console::Print("DeleteTimerQueue failed (%d)\n", GetLastError());
hTimer = NULL;
hTimerQueue = NULL;
return true;
}
// Else start a new callback timer
StartWait = true;
// Create the timer queue if needed
if (!hTimerQueue)
{
hTimerQueue = CreateTimerQueue();
if (NULL == hTimerQueue)
{
Console::Print("CreateTimerQueue failed (%d)\n", GetLastError());
return false;
}
}
// Set a timer to call the timer routine in 10 seconds.
if (!CreateTimerQueueTimer( &hTimer, hTimerQueue,
(WAITORTIMERCALLBACK)TimerRoutine, &Id , 10, 0, 0))
{
Console::Print("CreateTimerQueueTimer failed (%d)\n", GetLastError());
return false;
}
return false;
}
// Check if we are done or not
bool Event::DoneWait()
{
if (StartWait && DoneWaiting)
return true;
else
return false;
}
// Tells the timer that we are done waiting
void Event::SetTimer()
{
// We can not be done before we have started waiting
if (StartWait) DoneWaiting = true;
}
#endif
////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Supporting functions
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void SleepCurrentThread(int ms)
{
Sleep(ms);
}
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
@ -188,6 +309,8 @@ LONG SyncInterlockedExchange(LONG *Dest, LONG Val)
{
return InterlockedExchange(Dest, Val);
}
////////////////////////////////////////
#else // !WIN32, so must be POSIX threads

View File

@ -33,6 +33,15 @@
#include "Common.h"
// -----------------------------------------
#ifdef SETUP_TIMER_WAITING
// -----------------
typedef void (*EventCallBack)(void);
#endif
// ----------------------
namespace Common
{
class CriticalSection
@ -78,6 +87,7 @@ private:
};
class Event
{
public:
@ -89,6 +99,20 @@ public:
void Set();
void Wait();
// -----------------------------------------
#ifdef SETUP_TIMER_WAITING
// -----------------
bool TimerWait(EventCallBack WaitCB, int Id = 0, bool OptCondition = true);
bool DoneWait();
void SetTimer();
bool DoneWaiting;
bool StartWait;
int Id;
HANDLE hTimer;
HANDLE hTimerQueue;
#endif
// ---------------------------
private:
#ifdef _WIN32
HANDLE m_hEvent;