summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorSonicadvance1 <sonicadvance1@gmail.com>2010-04-29 13:46:20 +0000
committerSonicadvance1 <sonicadvance1@gmail.com>2010-04-29 13:46:20 +0000
commit81f06220cec97e093d75e862f98e4b2853cd89a7 (patch)
tree54cbfd17436694a82788b588724fee8ae8ca41ed /Source/Core
parent3103b920b6bc851a8a22735aed4755a9b12caa84 (diff)
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
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/Src/Thread.cpp940
-rw-r--r--Source/Core/Common/Src/Thread.h256
2 files changed, 542 insertions, 654 deletions
diff --git a/Source/Core/Common/Src/Thread.cpp b/Source/Core/Common/Src/Thread.cpp
index 01e6be0c37..8ac22356d9 100644
--- a/Source/Core/Common/Src/Thread.cpp
+++ b/Source/Core/Common/Src/Thread.cpp
@@ -17,7 +17,6 @@
#include "Setup.h"
#include "Thread.h"
-#include "Atomic.h"
#include "Common.h"
#ifdef USE_BEGINTHREADEX
@@ -26,588 +25,491 @@
namespace Common
{
-
-int Thread::CurrentId()
-{
- #ifdef _WIN32
+
+ int Thread::CurrentId()
+ {
+#ifdef _WIN32
return GetCurrentThreadId();
- #else
+#else
return 0;
- #endif
-}
-
+#endif
+ }
+
#ifdef _WIN32
-
-void InitThreading()
-{
- // Nothing to do in Win32 build.
-}
-
-CriticalSection::CriticalSection(int spincount)
-{
- if (spincount)
+
+ void InitThreading()
+ {
+ // Nothing to do in Win32 build.
+ }
+
+ CriticalSection::CriticalSection(int spincount)
+ {
+ if (spincount)
+ {
+ if (!InitializeCriticalSectionAndSpinCount(&section, spincount))
+ ERROR_LOG(COMMON, "CriticalSection could not be initialized!\n%s", GetLastErrorMsg());
+ }
+ else
+ {
+ InitializeCriticalSection(&section);
+ }
+ }
+
+ CriticalSection::~CriticalSection()
{
- if (!InitializeCriticalSectionAndSpinCount(&section, spincount))
- ERROR_LOG(COMMON, "CriticalSection could not be initialized!\n%s", GetLastErrorMsg());
+ DeleteCriticalSection(&section);
}
- else
+
+ void CriticalSection::Enter()
{
- InitializeCriticalSection(&section);
+ EnterCriticalSection(&section);
}
-}
-
-CriticalSection::~CriticalSection()
-{
- DeleteCriticalSection(&section);
-}
-
-void CriticalSection::Enter()
-{
- EnterCriticalSection(&section);
-}
-
-bool CriticalSection::TryEnter()
-{
- return TryEnterCriticalSection(&section) ? true : false;
-}
-
-void CriticalSection::Leave()
-{
- LeaveCriticalSection(&section);
-}
-
-Thread::Thread(ThreadFunc function, void* arg)
+
+ bool CriticalSection::TryEnter()
+ {
+ return TryEnterCriticalSection(&section) ? true : false;
+ }
+
+ void CriticalSection::Leave()
+ {
+ LeaveCriticalSection(&section);
+ }
+
+ 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);
+ m_hThread = (HANDLE)_beginthreadex(NULL, 0, function, arg, 0, &m_threadId);
#else
- m_hThread = CreateThread(NULL, 0, function, arg, 0, &m_threadId);
+ m_hThread = CreateThread(NULL, 0, function, arg, 0, &m_threadId);
#endif
-}
-
-Thread::~Thread()
-{
- WaitForDeath();
-}
-
-DWORD Thread::WaitForDeath(const int iWait)
-{
- if (m_hThread)
+ }
+
+ Thread::~Thread()
{
- DWORD Wait = WaitForSingleObject(m_hThread, iWait);
- CloseHandle(m_hThread);
- m_hThread = NULL;
- return Wait;
+ WaitForDeath();
}
- return NULL;
-}
-
-void Thread::SetAffinity(int mask)
-{
- SetThreadAffinityMask(m_hThread, mask);
-}
-
-void Thread::SetPriority(int priority)
-{
- SetThreadPriority(m_hThread, priority);
-}
-
-void Thread::SetCurrentThreadAffinity(int mask)
-{
- SetThreadAffinityMask(GetCurrentThread(), mask);
-}
-
-bool Thread::IsCurrentThread()
-{
- return GetCurrentThreadId() == m_threadId;
-}
-
-
-EventEx::EventEx()
-{
- InterlockedExchange(&m_Lock, 1);
-}
-
-void EventEx::Init()
-{
- InterlockedExchange(&m_Lock, 1);
-}
-
-void EventEx::Shutdown()
-{
- InterlockedExchange(&m_Lock, 0);
-}
-
-void EventEx::Set()
-{
- InterlockedExchange(&m_Lock, 0);
-}
-
-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()
-{
- while (InterlockedCompareExchange(&m_Lock, 1, 0))
- // This directly enters Ring0 and enforces a sleep about 15ms
- SleepCurrentThread(1);
-}
-
-bool EventEx::MsgWait()
-{
- while (InterlockedCompareExchange(&m_Lock, 1, 0))
+
+ DWORD Thread::WaitForDeath(const int iWait)
{
- MSG msg;
- while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ if (m_hThread)
{
- if (msg.message == WM_QUIT) return false;
- TranslateMessage(&msg);
- DispatchMessage(&msg);
+ DWORD Wait = WaitForSingleObject(m_hThread, iWait);
+ CloseHandle(m_hThread);
+ m_hThread = NULL;
+ return Wait;
}
- // This directly enters Ring0 and enforces a sleep about 15ms
- SleepCurrentThread(1);
+ return NULL;
}
- return true;
-}
-
-
-// Regular same thread loop based waiting
-Event::Event()
-{
- m_hEvent = 0;
-}
-
-void Event::Init()
-{
- m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-}
-
-void Event::Shutdown()
-{
- CloseHandle(m_hEvent);
- m_hEvent = 0;
-}
-
-void Event::Set()
-{
- SetEvent(m_hEvent);
-}
-
-bool Event::Wait(const u32 timeout)
-{
- return WaitForSingleObject(m_hEvent, timeout) != WAIT_OBJECT_0;
-}
-
-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.
- TranslateMessage(&msg);
- 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, THREAD_WAIT_TIMEOUT);
-
- // The result tells us the type of event we have.
- if (result == (WAIT_OBJECT_0 + 1))
+
+ void Thread::SetAffinity(int mask)
+ {
+ SetThreadAffinityMask(m_hThread, mask);
+ }
+
+ void Thread::SetPriority(int priority)
+ {
+ SetThreadPriority(m_hThread, priority);
+ }
+
+ void Thread::SetCurrentThreadAffinity(int mask)
+ {
+ SetThreadAffinityMask(GetCurrentThread(), mask);
+ }
+
+ bool Thread::IsCurrentThread()
+ {
+ return GetCurrentThreadId() == m_threadId;
+ }
+
+
+ EventEx::EventEx()
+ {
+ InterlockedExchange(&m_Lock, 1);
+ }
+
+ void EventEx::Init()
+ {
+ InterlockedExchange(&m_Lock, 1);
+ }
+
+ void EventEx::Shutdown()
+ {
+ InterlockedExchange(&m_Lock, 0);
+ }
+
+ void EventEx::Set()
+ {
+ InterlockedExchange(&m_Lock, 0);
+ }
+
+ 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()
+ {
+ while (InterlockedCompareExchange(&m_Lock, 1, 0))
+ // This directly enters Ring0 and enforces a sleep about 15ms
+ SleepCurrentThread(1);
+ }
+
+ bool EventEx::MsgWait()
+ {
+ while (InterlockedCompareExchange(&m_Lock, 1, 0))
{
- // New messages have arrived.
- // Continue to the top of the always while loop to
- // dispatch them and resume waiting.
- continue;
- }
- else
+ MSG msg;
+ while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+ {
+ if (msg.message == WM_QUIT) return false;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ // This directly enters Ring0 and enforces a sleep about 15ms
+ SleepCurrentThread(1);
+ }
+ return true;
+ }
+
+
+ // Regular same thread loop based waiting
+ Event::Event()
+ {
+ m_hEvent = 0;
+ }
+
+ void Event::Init()
+ {
+ m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ }
+
+ void Event::Shutdown()
+ {
+ CloseHandle(m_hEvent);
+ m_hEvent = 0;
+ }
+
+ void Event::Set()
+ {
+ SetEvent(m_hEvent);
+ }
+
+ bool Event::Wait(const u32 timeout)
+ {
+ return WaitForSingleObject(m_hEvent, timeout) != WAIT_OBJECT_0;
+ }
+
+ 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)
{
- // result == WAIT_OBJECT_0
- // Our event got signaled
- return;
+ 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.
+ TranslateMessage(&msg);
+ 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, THREAD_WAIT_TIMEOUT);
+
+ // 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;
+ }
}
}
-}
-
-// Supporting functions
-void SleepCurrentThread(int ms)
-{
- Sleep(ms);
-}
-
-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
-
-// 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
- //TODO: Find the proper way to do this.
- char tname[256];
- unsigned int i;
-
- for (i = 0; i < _tcslen(szThreadName); i++)
+
+ // Supporting functions
+ void SleepCurrentThread(int ms)
{
- tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
+ Sleep(ms);
}
-
- tname[i] = 0;
- info.szName = tname;
+
+ 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
+
+ // 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
+ //TODO: Find the proper way to do this.
+ char tname[256];
+ unsigned int i;
+
+ for (i = 0; i < _tcslen(szThreadName); i++)
+ {
+ tname[i] = (char)szThreadName[i]; //poor man's unicode->ansi, TODO: fix
+ }
+
+ tname[i] = 0;
+ info.szName = tname;
#else
- info.szName = szThreadName;
+ info.szName = szThreadName;
#endif
-
- info.dwThreadID = -1; //dwThreadID;
- info.dwFlags = 0;
- __try
- {
- RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
+
+ info.dwThreadID = -1; //dwThreadID;
+ info.dwFlags = 0;
+ __try
+ {
+ RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
+ }
+ __except(EXCEPTION_CONTINUE_EXECUTION)
+ {}
}
- __except(EXCEPTION_CONTINUE_EXECUTION)
- {}
-}
-
+
#else // !WIN32, so must be POSIX threads
-
-pthread_key_t threadname_key;
-
-CriticalSection::CriticalSection(int spincount_unused)
-{
- #ifdef __APPLE__
- lock = OS_SPINLOCK_INIT;
- #else
+
+ pthread_key_t threadname_key;
+
+ 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()
-{
- 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()
-{
- return(!pthread_mutex_trylock(&mutex));
-}
-
-
-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_id(0)
-{
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, 1024 * 1024);
- int ret = pthread_create(&thread_id, &attr, function, arg);
- if (ret) ERROR_LOG(COMMON, "%s: pthread_create(%p, %p, %p, %p) failed: %s\n",
- __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()
-{
- WaitForDeath();
-}
-
-
-void Thread::WaitForDeath()
-{
- if (thread_id)
+
+ void CriticalSection::Enter()
{
- void* exit_status;
- int ret = pthread_join(thread_id, &exit_status);
- if (ret) ERROR_LOG(COMMON, "error joining thread %lu: %s\n", thread_id, strerror(ret));
- if (exit_status)
- ERROR_LOG(COMMON, "thread %lu exited with status %d\n", thread_id, *(int *)exit_status);
- thread_id = 0;
+ int ret = pthread_mutex_lock(&mutex);
+ if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_lock(%p) failed: %s\n",
+ __FUNCTION__, &mutex, strerror(ret));
}
-}
-
-
-void Thread::SetAffinity(int mask)
-{
- // This is non-standard
-#ifdef __linux__
- cpu_set_t cpu_set;
- CPU_ZERO(&cpu_set);
-
- for (unsigned int i = 0; i < sizeof(mask) * 8; i++)
+
+
+ bool CriticalSection::TryEnter()
{
- if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
+ return(!pthread_mutex_trylock(&mutex));
}
-
- pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
-#endif
-}
-
-void Thread::SetCurrentThreadAffinity(int mask)
-{
-#ifdef __linux__
- cpu_set_t cpu_set;
- CPU_ZERO(&cpu_set);
-
- for (size_t i = 0; i < sizeof(mask) * 8; i++)
+
+
+ void CriticalSection::Leave()
{
- if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
+ int ret = pthread_mutex_unlock(&mutex);
+ if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_unlock(%p) failed: %s\n",
+ __FUNCTION__, &mutex, strerror(ret));
}
-
- pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
-#endif
-}
-
-bool Thread::IsCurrentThread()
-{
- return pthread_equal(pthread_self(), thread_id) != 0;
-}
-
-void InitThreading() {
- static int thread_init_done = 0;
- if (thread_init_done)
- return;
- if (pthread_key_create(&threadname_key, NULL/*free*/) != 0)
- perror("Unable to create thread name key: ");
-
- thread_init_done++;
-}
-
-void SleepCurrentThread(int ms)
-{
- usleep(1000 * ms);
-}
-
-
-void SetCurrentThreadName(const TCHAR* szThreadName)
-{
- char *name = strdup(szThreadName);
- // pthread_setspecific returns 0 on success
- // free the string from strdup if fails
- // creates a memory leak if it actually doesn't fail
- // since we don't delete it once we delete the thread
- // we are using a single threadname_key anyway for all threads
- 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
- is_set_ = false;
-}
-
-
-void Event::Init()
-{
-#ifndef __APPLE__
- pthread_cond_init(&event_, 0);
- pthread_mutex_init(&mutex_, 0);
-#else
- lock = OS_SPINLOCK_INIT;
- event_ = 0;
-#endif
-}
-
-
-void Event::Shutdown()
-{
-#ifndef __APPLE__
- pthread_mutex_destroy(&mutex_);
- pthread_cond_destroy(&event_);
-#endif
-}
-
-#ifdef __APPLE__
-void Event::Set()
-{
- OSSpinLockLock(&lock);
-
- if (!is_set_)
+
+ Thread::Thread(ThreadFunc function, void* arg)
+ : thread_id(0)
{
- is_set_ = true;
- Common::AtomicStore(event_, 1);
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 1024 * 1024);
+ int ret = pthread_create(&thread_id, &attr, function, arg);
+ if (ret) ERROR_LOG(COMMON, "%s: pthread_create(%p, %p, %p, %p) failed: %s\n",
+ __FUNCTION__, &thread_id, &attr, function, arg, strerror(ret));
+
+ INFO_LOG(COMMON, "created new thread %lu (func=%p, arg=%p)\n", thread_id, function, arg);
}
-
- OSSpinLockUnlock(&lock);
-}
-
-
-bool Event::Wait(const u32 timeout)
-{
- bool timedout = false;
- struct timespec wait;
-
- if (timeout != INFINITE)
+
+
+ Thread::~Thread()
{
- 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);
+ WaitForDeath();
}
- int Slept = 0;
- while (!timedout)
+
+ void Thread::WaitForDeath()
{
- if (timeout == INFINITE)
+ if (thread_id)
{
- if(Common::AtomicLoad(event_) == 1)
- break;
+ void* exit_status;
+ int ret = pthread_join(thread_id, &exit_status);
+ if (ret) ERROR_LOG(COMMON, "error joining thread %lu: %s\n", thread_id, strerror(ret));
+ if (exit_status)
+ ERROR_LOG(COMMON, "thread %lu exited with status %d\n", thread_id, *(int *)exit_status);
+ thread_id = 0;
}
- else
+ }
+
+
+ void Thread::SetAffinity(int mask)
+ {
+ // This is non-standard
+#ifdef __linux__
+ cpu_set_t cpu_set;
+ CPU_ZERO(&cpu_set);
+
+ for (unsigned int i = 0; i < sizeof(mask) * 8; i++)
{
- if(Slept >= wait.tv_sec * 1000000)
- timedout = true;
- else
- if(Common::AtomicLoad(event_) == 1)
- break;
+ if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
}
- usleep(250);
- Slept += 250;
+
+ pthread_setaffinity_np(thread_id, sizeof(cpu_set), &cpu_set);
+#endif
}
-
- OSSpinLockLock(&lock);
- is_set_ = false;
- Common::AtomicStore(event_, 0);
- OSSpinLockUnlock(&lock);
- return timedout;
-}
-#else
-void Event::Set()
-{
- pthread_mutex_lock(&mutex_);
+ void Thread::SetCurrentThreadAffinity(int mask)
+ {
+#ifdef __linux__
+ cpu_set_t cpu_set;
+ CPU_ZERO(&cpu_set);
+
+ for (size_t i = 0; i < sizeof(mask) * 8; i++)
+ {
+ if ((mask >> i) & 1){CPU_SET(i, &cpu_set);}
+ }
+
+ pthread_setaffinity_np(pthread_self(), sizeof(cpu_set), &cpu_set);
+#endif
+ }
- if (!is_set_)
+ bool Thread::IsCurrentThread()
{
- is_set_ = true;
- pthread_cond_signal(&event_);
+ return pthread_equal(pthread_self(), thread_id) != 0;
}
- pthread_mutex_unlock(&mutex_);
-}
-
-
-bool Event::Wait(const u32 timeout)
-{
- bool timedout = false;
- struct timespec wait;
- pthread_mutex_lock(&mutex_);
+ void InitThreading() {
+ static int thread_init_done = 0;
+ if (thread_init_done)
+ return;
+
+ if (pthread_key_create(&threadname_key, NULL/*free*/) != 0)
+ perror("Unable to create thread name key: ");
+
+ thread_init_done++;
+ }
- if (timeout != INFINITE)
+ void SleepCurrentThread(int ms)
{
- struct timeval now;
- gettimeofday(&now, NULL);
+ usleep(1000 * ms);
+ }
+
+
+ void SetCurrentThreadName(const TCHAR* szThreadName)
+ {
+ char *name = strdup(szThreadName);
+ // pthread_setspecific returns 0 on success
+ // free the string from strdup if fails
+ // creates a memory leak if it actually doesn't fail
+ // since we don't delete it once we delete the thread
+ // we are using a single threadname_key anyway for all threads
+ if(!pthread_setspecific(threadname_key, name))
+ free(name);
+ INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName);
+ }
+
+
+ Event::Event()
+ {
+ is_set_ = false;
+ }
+
+
+ void Event::Init()
+ {
+ pthread_cond_init(&event_, 0);
+ pthread_mutex_init(&mutex_, 0);
+ }
+
+
+ void Event::Shutdown()
+ {
+ pthread_mutex_destroy(&mutex_);
+ pthread_cond_destroy(&event_);
+ }
+
+
+ void Event::Set()
+ {
+ pthread_mutex_lock(&mutex_);
+
+ if (!is_set_)
+ {
+ is_set_ = true;
+ pthread_cond_signal(&event_);
+ }
- 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);
+ pthread_mutex_unlock(&mutex_);
}
- while (!is_set_ && !timedout)
+
+ bool Event::Wait(const u32 timeout)
{
- if (timeout == INFINITE)
+ bool timedout = false;
+ struct timespec wait;
+ pthread_mutex_lock(&mutex_);
+
+ if (timeout != INFINITE)
{
- pthread_cond_wait(&event_, &mutex_);
+ 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);
}
- else
+
+ while (!is_set_ && !timedout)
{
- timedout = pthread_cond_timedwait(&event_, &mutex_, &wait) == ETIMEDOUT;
+ if (timeout == INFINITE)
+ {
+ pthread_cond_wait(&event_, &mutex_);
+ }
+ else
+ {
+ timedout = pthread_cond_timedwait(&event_, &mutex_, &wait) == ETIMEDOUT;
+ }
}
+
+ is_set_ = false;
+ pthread_mutex_unlock(&mutex_);
+
+ return timedout;
}
- is_set_ = false;
- pthread_mutex_unlock(&mutex_);
-
- return timedout;
-}
-#endif
-
#endif
-
+
} // namespace Common
diff --git a/Source/Core/Common/Src/Thread.h b/Source/Core/Common/Src/Thread.h
index 6147ec712b..584fd88613 100644
--- a/Source/Core/Common/Src/Thread.h
+++ b/Source/Core/Common/Src/Thread.h
@@ -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>
@@ -72,169 +68,159 @@
namespace Common
{
-
-class CriticalSection
-{
+
+ class CriticalSection
+ {
#ifdef _WIN32
- CRITICAL_SECTION section;
+ CRITICAL_SECTION section;
#else
#ifdef _POSIX_THREADS
- #ifdef __APPLE__
- OSSpinLock lock;
- #else
pthread_mutex_t mutex;
- #endif
#endif
#endif
-public:
-
- CriticalSection(int spincount = 1000);
- ~CriticalSection();
- void Enter();
- bool TryEnter();
- void Leave();
-};
-
+ 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);
-
-#endif
-
-class Thread
-{
-public:
- Thread(ThreadFunc entry, void* arg);
- ~Thread();
-
- void SetAffinity(int mask);
- static void SetCurrentThreadAffinity(int mask);
- static int CurrentId();
- bool IsCurrentThread();
+
+ typedef void* (*ThreadFunc)(void* arg);
+
+#endif
+
+ class Thread
+ {
+ public:
+ Thread(ThreadFunc entry, void* arg);
+ ~Thread();
+
+ void SetAffinity(int mask);
+ static void SetCurrentThreadAffinity(int mask);
+ static int CurrentId();
+ bool IsCurrentThread();
#ifdef _WIN32
- void SetPriority(int priority);
- DWORD WaitForDeath(const int iWait = INFINITE);
+ void SetPriority(int priority);
+ DWORD WaitForDeath(const int iWait = INFINITE);
#else
- void WaitForDeath();
+ void WaitForDeath();
#endif
-
-private:
-
+
+ private:
+
#ifdef _WIN32
-
- HANDLE m_hThread;
+
+ HANDLE m_hThread;
#ifdef USE_BEGINTHREADEX
- unsigned m_threadId;
+ unsigned m_threadId;
#else
- DWORD m_threadId;
+ DWORD m_threadId;
#endif
-
+
#else
-
+
#ifdef _POSIX_THREADS
- pthread_t thread_id;
+ pthread_t thread_id;
#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:
- EventEx();
- void Init();
- void Shutdown();
- void Set();
- // Infinite wait
- void Spin();
- // Infinite wait with sleep
- void Wait();
- // Wait with message processing and sleep
- bool MsgWait();
-private:
- volatile long m_Lock;
-};
+ // 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();
+ void Set();
+ // Infinite wait
+ void Spin();
+ // Infinite wait with sleep
+ void Wait();
+ // Wait with message processing and sleep
+ bool MsgWait();
+ private:
+ volatile long m_Lock;
+ };
#else
-// TODO: implement for Linux
+ // TODO: implement for Linux
#define EventEx Event
#endif
-
-class Event
-{
-public:
- Event();
-
- void Init();
- void Shutdown();
-
- void Set();
- //returns whether the wait timed out
- bool Wait(const u32 timeout = INFINITE);
+
+ class Event
+ {
+ public:
+ Event();
+ void Init();
+ void Shutdown();
+
+ void Set();
+ //returns whether the wait timed out
+ bool Wait(const u32 timeout = INFINITE);
#ifdef _WIN32
- void MsgWait();
+ void MsgWait();
#else
- void MsgWait() {Wait();}
+ void MsgWait() {Wait();}
#endif
-
-
-private:
+
+
+ private:
#ifdef _WIN32
-
- HANDLE m_hEvent;
- /* If we have waited more than five seconds we can be pretty sure that the thread is deadlocked.
- So then we can just as well continue and hope for the best. I could try several times that
- this works after a five second timeout (with works meaning that the game stopped and I could
- start another game without any noticable problems). But several times it failed to, and ended
- with a crash. But it's better than an infinite deadlock. */
- static const int THREAD_WAIT_TIMEOUT = 5000; // INFINITE or 5000 for example
-
+
+ HANDLE m_hEvent;
+ /* If we have waited more than five seconds we can be pretty sure that the thread is deadlocked.
+ So then we can just as well continue and hope for the best. I could try several times that
+ this works after a five second timeout (with works meaning that the game stopped and I could
+ start another game without any noticable problems). But several times it failed to, and ended
+ with a crash. But it's better than an infinite deadlock. */
+ static const int THREAD_WAIT_TIMEOUT = 5000; // INFINITE or 5000 for example
+
#else
-
- bool is_set_;
+
+ 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);
-
-// 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()
-{
+ pthread_cond_t event_;
+ pthread_mutex_t mutex_;
+#endif
+
+#endif
+ };
+
+ 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()
+ {
#ifdef _WIN32
- YieldProcessor();
+ YieldProcessor();
#elif defined(_M_IX86) || defined(_M_X64)
- _mm_pause();
+ _mm_pause();
#endif
-}
-
-void SetCurrentThreadName(const char *name);
-
+ }
+
+ void SetCurrentThreadName(const char *name);
+
} // namespace Common
#endif // _THREAD_H_