Massive Poo storm, had to take shelter. Hacks, fixes, etc etc

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5421 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Sonicadvance1 2010-04-29 13:46:20 +00:00
parent 3103b920b6
commit 81f06220ce
2 changed files with 567 additions and 679 deletions

View File

@ -17,7 +17,6 @@
#include "Setup.h"
#include "Thread.h"
#include "Atomic.h"
#include "Common.h"
#ifdef USE_BEGINTHREADEX
@ -27,24 +26,24 @@
namespace Common
{
int Thread::CurrentId()
{
#ifdef _WIN32
int Thread::CurrentId()
{
#ifdef _WIN32
return GetCurrentThreadId();
#else
#else
return 0;
#endif
}
#endif
}
#ifdef _WIN32
void InitThreading()
{
void InitThreading()
{
// Nothing to do in Win32 build.
}
}
CriticalSection::CriticalSection(int spincount)
{
CriticalSection::CriticalSection(int spincount)
{
if (spincount)
{
if (!InitializeCriticalSectionAndSpinCount(&section, spincount))
@ -54,45 +53,45 @@ CriticalSection::CriticalSection(int spincount)
{
InitializeCriticalSection(&section);
}
}
}
CriticalSection::~CriticalSection()
{
CriticalSection::~CriticalSection()
{
DeleteCriticalSection(&section);
}
}
void CriticalSection::Enter()
{
void CriticalSection::Enter()
{
EnterCriticalSection(&section);
}
}
bool CriticalSection::TryEnter()
{
bool CriticalSection::TryEnter()
{
return TryEnterCriticalSection(&section) ? true : false;
}
}
void CriticalSection::Leave()
{
void CriticalSection::Leave()
{
LeaveCriticalSection(&section);
}
}
Thread::Thread(ThreadFunc function, void* arg)
Thread::Thread(ThreadFunc function, void* arg)
: m_hThread(NULL), m_threadId(0)
{
{
#ifdef USE_BEGINTHREADEX
m_hThread = (HANDLE)_beginthreadex(NULL, 0, function, arg, 0, &m_threadId);
#else
m_hThread = CreateThread(NULL, 0, function, arg, 0, &m_threadId);
#endif
}
}
Thread::~Thread()
{
Thread::~Thread()
{
WaitForDeath();
}
}
DWORD Thread::WaitForDeath(const int iWait)
{
DWORD Thread::WaitForDeath(const int iWait)
{
if (m_hThread)
{
DWORD Wait = WaitForSingleObject(m_hThread, iWait);
@ -101,66 +100,66 @@ DWORD Thread::WaitForDeath(const int iWait)
return Wait;
}
return NULL;
}
}
void Thread::SetAffinity(int mask)
{
void Thread::SetAffinity(int mask)
{
SetThreadAffinityMask(m_hThread, mask);
}
}
void Thread::SetPriority(int priority)
{
void Thread::SetPriority(int priority)
{
SetThreadPriority(m_hThread, priority);
}
}
void Thread::SetCurrentThreadAffinity(int mask)
{
void Thread::SetCurrentThreadAffinity(int mask)
{
SetThreadAffinityMask(GetCurrentThread(), mask);
}
}
bool Thread::IsCurrentThread()
{
bool Thread::IsCurrentThread()
{
return GetCurrentThreadId() == m_threadId;
}
}
EventEx::EventEx()
{
EventEx::EventEx()
{
InterlockedExchange(&m_Lock, 1);
}
}
void EventEx::Init()
{
void EventEx::Init()
{
InterlockedExchange(&m_Lock, 1);
}
}
void EventEx::Shutdown()
{
void EventEx::Shutdown()
{
InterlockedExchange(&m_Lock, 0);
}
}
void EventEx::Set()
{
void EventEx::Set()
{
InterlockedExchange(&m_Lock, 0);
}
}
void EventEx::Spin()
{
void EventEx::Spin()
{
while (InterlockedCompareExchange(&m_Lock, 1, 0))
// This only yields when there is a runnable thread on this core
// If not, spin
SwitchToThread();
}
}
void EventEx::Wait()
{
void EventEx::Wait()
{
while (InterlockedCompareExchange(&m_Lock, 1, 0))
// This directly enters Ring0 and enforces a sleep about 15ms
SleepCurrentThread(1);
}
}
bool EventEx::MsgWait()
{
bool EventEx::MsgWait()
{
while (InterlockedCompareExchange(&m_Lock, 1, 0))
{
MSG msg;
@ -174,43 +173,43 @@ bool EventEx::MsgWait()
SleepCurrentThread(1);
}
return true;
}
}
// Regular same thread loop based waiting
Event::Event()
{
// Regular same thread loop based waiting
Event::Event()
{
m_hEvent = 0;
}
}
void Event::Init()
{
void Event::Init()
{
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}
}
void Event::Shutdown()
{
void Event::Shutdown()
{
CloseHandle(m_hEvent);
m_hEvent = 0;
}
}
void Event::Set()
{
void Event::Set()
{
SetEvent(m_hEvent);
}
}
bool Event::Wait(const u32 timeout)
{
bool Event::Wait(const u32 timeout)
{
return WaitForSingleObject(m_hEvent, timeout) != WAIT_OBJECT_0;
}
}
inline HRESULT MsgWaitForSingleObject(HANDLE handle, DWORD timeout)
{
inline HRESULT MsgWaitForSingleObject(HANDLE handle, DWORD timeout)
{
return MsgWaitForMultipleObjects(1, &handle, FALSE, timeout, 0);
}
}
void Event::MsgWait()
{
void Event::MsgWait()
{
// Adapted from MSDN example http://msdn.microsoft.com/en-us/library/ms687060.aspx
while (true)
{
@ -247,31 +246,31 @@ void Event::MsgWait()
return;
}
}
}
}
// Supporting functions
void SleepCurrentThread(int ms)
{
// Supporting functions
void SleepCurrentThread(int ms)
{
Sleep(ms);
}
}
typedef struct tagTHREADNAME_INFO
{
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1=caller thread)
DWORD dwFlags; // reserved for future use, must be zero
} THREADNAME_INFO;
// Usage: SetThreadName (-1, "MainThread");
//
// Sets the debugger-visible name of the current thread.
// Uses undocumented (actually, it is now documented) trick.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
} THREADNAME_INFO;
// Usage: SetThreadName (-1, "MainThread");
//
// Sets the debugger-visible name of the current thread.
// Uses undocumented (actually, it is now documented) trick.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
// This is implemented much nicer in upcoming msvc++, see:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
void SetCurrentThreadName(const TCHAR* szThreadName)
{
// This is implemented much nicer in upcoming msvc++, see:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
void SetCurrentThreadName(const TCHAR* szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
#ifdef UNICODE
@ -298,73 +297,49 @@ void SetCurrentThreadName(const TCHAR* szThreadName)
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{}
}
}
#else // !WIN32, so must be POSIX threads
pthread_key_t threadname_key;
pthread_key_t threadname_key;
CriticalSection::CriticalSection(int spincount_unused)
{
#ifdef __APPLE__
lock = OS_SPINLOCK_INIT;
#else
CriticalSection::CriticalSection(int spincount_unused)
{
pthread_mutex_init(&mutex, NULL);
#endif
}
}
CriticalSection::~CriticalSection()
{
#ifndef __APPLE__
CriticalSection::~CriticalSection()
{
pthread_mutex_destroy(&mutex);
#endif
}
}
#ifndef __APPLE__
void CriticalSection::Enter()
{
void CriticalSection::Enter()
{
int ret = pthread_mutex_lock(&mutex);
if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_lock(%p) failed: %s\n",
__FUNCTION__, &mutex, strerror(ret));
}
}
bool CriticalSection::TryEnter()
{
bool CriticalSection::TryEnter()
{
return(!pthread_mutex_trylock(&mutex));
}
}
void CriticalSection::Leave()
{
void CriticalSection::Leave()
{
int ret = pthread_mutex_unlock(&mutex);
if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_unlock(%p) failed: %s\n",
__FUNCTION__, &mutex, strerror(ret));
}
#else
void CriticalSection::Enter()
{
OSSpinLockLock(&lock);
}
}
bool CriticalSection::TryEnter()
{
return(!OSSpinLockTry(&lock));
}
void CriticalSection::Leave()
{
OSSpinLockUnlock(&lock);
}
#endif
Thread::Thread(ThreadFunc function, void* arg)
Thread::Thread(ThreadFunc function, void* arg)
: thread_id(0)
{
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024 * 1024);
@ -373,17 +348,17 @@ Thread::Thread(ThreadFunc function, void* arg)
__FUNCTION__, &thread_id, &attr, function, arg, strerror(ret));
INFO_LOG(COMMON, "created new thread %lu (func=%p, arg=%p)\n", thread_id, function, arg);
}
}
Thread::~Thread()
{
Thread::~Thread()
{
WaitForDeath();
}
}
void Thread::WaitForDeath()
{
void Thread::WaitForDeath()
{
if (thread_id)
{
void* exit_status;
@ -393,11 +368,11 @@ void Thread::WaitForDeath()
ERROR_LOG(COMMON, "thread %lu exited with status %d\n", thread_id, *(int *)exit_status);
thread_id = 0;
}
}
}
void Thread::SetAffinity(int mask)
{
void Thread::SetAffinity(int mask)
{
// This is non-standard
#ifdef __linux__
cpu_set_t cpu_set;
@ -410,10 +385,10 @@ void Thread::SetAffinity(int mask)
pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
#endif
}
}
void Thread::SetCurrentThreadAffinity(int mask)
{
void Thread::SetCurrentThreadAffinity(int mask)
{
#ifdef __linux__
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
@ -425,14 +400,14 @@ void Thread::SetCurrentThreadAffinity(int mask)
pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
#endif
}
}
bool Thread::IsCurrentThread()
{
bool Thread::IsCurrentThread()
{
return pthread_equal(pthread_self(), thread_id) != 0;
}
}
void InitThreading() {
void InitThreading() {
static int thread_init_done = 0;
if (thread_init_done)
return;
@ -441,16 +416,16 @@ void InitThreading() {
perror("Unable to create thread name key: ");
thread_init_done++;
}
}
void SleepCurrentThread(int ms)
{
void SleepCurrentThread(int ms)
{
usleep(1000 * ms);
}
}
void SetCurrentThreadName(const TCHAR* szThreadName)
{
void SetCurrentThreadName(const TCHAR* szThreadName)
{
char *name = strdup(szThreadName);
// pthread_setspecific returns 0 on success
// free the string from strdup if fails
@ -460,103 +435,31 @@ void SetCurrentThreadName(const TCHAR* szThreadName)
if(!pthread_setspecific(threadname_key, name))
free(name);
INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName);
}
}
Event::Event()
{
#ifdef __APPLE__
lock = OS_SPINLOCK_INIT;
event_ = 0;
#endif
Event::Event()
{
is_set_ = false;
}
}
void Event::Init()
{
#ifndef __APPLE__
void Event::Init()
{
pthread_cond_init(&event_, 0);
pthread_mutex_init(&mutex_, 0);
#else
lock = OS_SPINLOCK_INIT;
event_ = 0;
#endif
}
}
void Event::Shutdown()
{
#ifndef __APPLE__
void Event::Shutdown()
{
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&event_);
#endif
}
#ifdef __APPLE__
void Event::Set()
{
OSSpinLockLock(&lock);
if (!is_set_)
{
is_set_ = true;
Common::AtomicStore(event_, 1);
}
OSSpinLockUnlock(&lock);
}
bool Event::Wait(const u32 timeout)
{
bool timedout = false;
struct timespec wait;
if (timeout != INFINITE)
void Event::Set()
{
struct timeval now;
gettimeofday(&now, NULL);
memset(&wait, 0, sizeof(wait));
//TODO: timespec also has nanoseconds, but do we need them?
//as consequence, waiting is limited to seconds for now.
//the following just looks ridiculous, and probably fails for
//values 429 < ms <= 999 since it overflows the long.
//wait.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000);
wait.tv_sec = now.tv_sec + (timeout / 1000);
}
int Slept = 0;
while (!timedout)
{
if (timeout == INFINITE)
{
if(Common::AtomicLoad(event_) == 1)
break;
}
else
{
if(Slept >= wait.tv_sec * 1000000)
timedout = true;
else
if(Common::AtomicLoad(event_) == 1)
break;
}
usleep(250);
Slept += 250;
}
OSSpinLockLock(&lock);
is_set_ = false;
Common::AtomicStore(event_, 0);
OSSpinLockUnlock(&lock);
return timedout;
}
#else
void Event::Set()
{
pthread_mutex_lock(&mutex_);
if (!is_set_)
@ -566,11 +469,11 @@ void Event::Set()
}
pthread_mutex_unlock(&mutex_);
}
}
bool Event::Wait(const u32 timeout)
{
bool Event::Wait(const u32 timeout)
{
bool timedout = false;
struct timespec wait;
pthread_mutex_lock(&mutex_);
@ -605,8 +508,7 @@ bool Event::Wait(const u32 timeout)
pthread_mutex_unlock(&mutex_);
return timedout;
}
#endif
}
#endif

View File

@ -47,10 +47,6 @@
#error unsupported platform (no pthreads?)
#endif
#ifdef __APPLE__
#include <libkern/OSAtomic.h>
#endif
#endif
// Don't include common.h here as it will break LogManager
@ -60,9 +56,9 @@
// This may not be defined outside _WIN32
#ifndef _WIN32
#ifndef INFINITE
#define INFINITE 0xffffffff
#endif
#ifndef INFINITE
#define INFINITE 0xffffffff
#endif
//for gettimeofday and struct time(val|spec)
#include <sys/time.h>
@ -73,45 +69,41 @@
namespace Common
{
class CriticalSection
{
class CriticalSection
{
#ifdef _WIN32
CRITICAL_SECTION section;
#else
#ifdef _POSIX_THREADS
#ifdef __APPLE__
OSSpinLock lock;
#else
pthread_mutex_t mutex;
#endif
#endif
#endif
public:
public:
CriticalSection(int spincount = 1000);
~CriticalSection();
void Enter();
bool TryEnter();
void Leave();
};
};
#ifdef _WIN32
#ifdef USE_BEGINTHREADEX
typedef unsigned (__stdcall *ThreadFunc)(void* arg);
typedef unsigned (__stdcall *ThreadFunc)(void* arg);
#else
typedef DWORD (WINAPI *ThreadFunc)(void* arg);
typedef DWORD (WINAPI *ThreadFunc)(void* arg);
#endif
#else
typedef void* (*ThreadFunc)(void* arg);
typedef void* (*ThreadFunc)(void* arg);
#endif
class Thread
{
public:
class Thread
{
public:
Thread(ThreadFunc entry, void* arg);
~Thread();
@ -126,7 +118,7 @@ public:
void WaitForDeath();
#endif
private:
private:
#ifdef _WIN32
@ -144,16 +136,16 @@ private:
#endif
#endif
};
};
#ifdef _WIN32
// Event(WaitForSingleObject) is too expensive
// as it always enters Ring0 regardless of the state of lock
// This EventEx will try to stay in Ring3 as much as possible
// If the lock can be obtained in the first time, Ring0 won't be entered at all
class EventEx
{
public:
// Event(WaitForSingleObject) is too expensive
// as it always enters Ring0 regardless of the state of lock
// This EventEx will try to stay in Ring3 as much as possible
// If the lock can be obtained in the first time, Ring0 won't be entered at all
class EventEx
{
public:
EventEx();
void Init();
void Shutdown();
@ -164,19 +156,18 @@ public:
void Wait();
// Wait with message processing and sleep
bool MsgWait();
private:
private:
volatile long m_Lock;
};
};
#else
// TODO: implement for Linux
// TODO: implement for Linux
#define EventEx Event
#endif
class Event
{
public:
class Event
{
public:
Event();
void Init();
void Shutdown();
@ -190,7 +181,7 @@ public:
#endif
private:
private:
#ifdef _WIN32
HANDLE m_hEvent;
@ -205,35 +196,30 @@ private:
bool is_set_;
#ifdef _POSIX_THREADS
#ifdef __APPLE__
OSSpinLock lock;
u32 event_;
#else
pthread_cond_t event_;
pthread_mutex_t mutex_;
#endif
#endif
#endif
};
};
void InitThreading();
void SleepCurrentThread(int ms);
void InitThreading();
void SleepCurrentThread(int ms);
// YieldCPU: This function is only effective on HyperThreading CPU
// Use this function during a spin-wait to make the current thread
// relax while another thread is working. This may be more efficient
// than using events because event functions use kernel calls.
inline void YieldCPU()
{
// YieldCPU: This function is only effective on HyperThreading CPU
// Use this function during a spin-wait to make the current thread
// relax while another thread is working. This may be more efficient
// than using events because event functions use kernel calls.
inline void YieldCPU()
{
#ifdef _WIN32
YieldProcessor();
#elif defined(_M_IX86) || defined(_M_X64)
_mm_pause();
#endif
}
}
void SetCurrentThreadName(const char *name);
void SetCurrentThreadName(const char *name);
} // namespace Common