Replaced Common::CriticalSection with a std::mutex implementation. 64bit Windows builds now use SRWLocks and ConditionVariables(requires Vista/7, x64 builds will no longer work on Windows XP x64). Tell me if you hate that. Removed Common::EventEx. Common::Event now uses a std::condition_variable impl.(using ConditionVariables on Windows x64, Events on x86, or posix condition variables elsewhere). I experience slight speed improvements with these changes.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7294 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak
2011-03-05 06:11:26 +00:00
parent a037ff2358
commit 423018f811
56 changed files with 918 additions and 835 deletions

View File

@ -36,9 +36,8 @@ void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
LogManager *LogManager::m_logManager = NULL;
LogManager::LogManager() {
logMutex = new Common::CriticalSection(1);
LogManager::LogManager()
{
// create log files
m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
@ -105,7 +104,6 @@ LogManager::~LogManager() {
delete m_fileLog;
delete m_consoleLog;
delete logMutex;
}
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
@ -127,15 +125,14 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
file, line, level_to_char[(int)level],
log->getShortName(), temp);
logMutex->Enter();
std::lock_guard<std::mutex> lk(logMutex);
log->trigger(level, msg);
logMutex->Leave();
}
void LogManager::removeListener(LogTypes::LOG_TYPE type, LogListener *listener) {
logMutex->Enter();
void LogManager::removeListener(LogTypes::LOG_TYPE type, LogListener *listener)
{
std::lock_guard<std::mutex> lk(logMutex);
m_Log[type]->removeListener(listener);
logMutex->Leave();
}
void LogManager::Init()

View File

@ -20,6 +20,7 @@
#include "Log.h"
#include "StringUtil.h"
#include "Thread.h"
#include <vector>
#include <string.h>
@ -102,16 +103,11 @@ private:
class ConsoleListener;
// Avoid <windows.h> include through Thread.h
namespace Common {
class CriticalSection;
}
class LogManager : NonCopyable
{
private:
LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
Common::CriticalSection *logMutex;
std::mutex logMutex;
FileLogListener *m_fileLog;
ConsoleListener *m_consoleLog;
static LogManager *m_logManager; // Singleton. Ugh.

View File

@ -0,0 +1,152 @@
#ifndef CONDITION_VARIABLE_H_
#define CONDITION_VARIABLE_H_
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
// GCC 4.4 provides <condition_variable>
#include <condition_variable>
#else
// partial std::condition_variable implementation for win32/pthread
#include "StdMutex.h"
#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
#define USE_RVALUE_REFERENCES
#endif
#if defined(_WIN32) && defined(_M_X64)
#define USE_CONDITION_VARIABLES
#elif defined(_WIN32)
#define USE_EVENTS
#endif
namespace std
{
class condition_variable
{
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
typedef CONDITION_VARIABLE native_type;
#elif defined(_WIN32)
typedef HANDLE native_type;
#else
typedef pthread_cond_t native_type;
#endif
public:
#ifdef USE_EVENTS
typedef native_type native_handle_type;
#else
typedef native_type* native_handle_type;
#endif
condition_variable()
{
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
InitializeConditionVariable(&m_handle);
#elif defined(_WIN32)
m_handle = CreateEvent(NULL, false, false, NULL);
#else
pthread_cond_init(&m_handle, NULL);
#endif
}
~condition_variable()
{
#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES)
CloseHandle(m_handle);
#elif !defined(_WIN32)
pthread_cond_destroy(&m_handle);
#endif
}
condition_variable(const condition_variable&) /*= delete*/;
condition_variable& operator=(const condition_variable&) /*= delete*/;
void notify_one()
{
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
WakeConditionVariable(&m_handle);
#elif defined(_WIN32)
SetEvent(m_handle);
#else
pthread_cond_signal(&m_handle);
#endif
}
void notify_all()
{
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
WakeAllConditionVariable(&m_handle);
#elif defined(_WIN32)
// TODO: broken
SetEvent(m_handle);
#else
pthread_cond_broadcast(&m_handle);
#endif
}
void wait(unique_lock<mutex>& lock)
{
#ifdef _WIN32
#ifdef USE_SRWLOCKS
SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0);
#elif USE_CONDITION_VARIABLES
SleepConditionVariableCS(m_handle, lock.mutex()->native_handle(), INFINITE);
#else
lock.unlock();
WaitForSingleObject(m_handle, INFINITE);
lock.lock();
#endif
#else
pthread_cond_wait(&m_handle, lock.mutex()->native_handle());
#endif
}
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred)
{
while (!pred())
wait(lock);
}
//template <class Clock, class Duration>
//cv_status wait_until(unique_lock<mutex>& lock,
// const chrono::time_point<Clock, Duration>& abs_time);
//template <class Clock, class Duration, class Predicate>
// bool wait_until(unique_lock<mutex>& lock,
// const chrono::time_point<Clock, Duration>& abs_time,
// Predicate pred);
//template <class Rep, class Period>
//cv_status wait_for(unique_lock<mutex>& lock,
// const chrono::duration<Rep, Period>& rel_time);
//template <class Rep, class Period, class Predicate>
// bool wait_for(unique_lock<mutex>& lock,
// const chrono::duration<Rep, Period>& rel_time,
// Predicate pred);
native_handle_type native_handle()
{
#ifdef USE_EVENTS
return m_handle;
#else
return &m_handle;
#endif
}
private:
native_type m_handle;
};
}
#endif
#endif

View File

@ -0,0 +1,352 @@
#ifndef MUTEX_H_
#define MUTEX_H_
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
// GCC 4.4 provides <mutex>
#include <mutex>
#else
// partial <mutex> implementation for win32/pthread
#include <algorithm>
#if defined(_WIN32)
// WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#else
// POSIX
#include <pthread.h>
#endif
#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
#define USE_RVALUE_REFERENCES
#endif
#if defined(_WIN32) && defined(_M_X64)
#define USE_SRWLOCKS
#endif
namespace std
{
class recursive_mutex
{
#ifdef _WIN32
typedef CRITICAL_SECTION native_type;
#else
typedef pthread_mutex_t native_type;
#endif
public:
typedef native_type* native_handle_type;
recursive_mutex(const recursive_mutex&) /*= delete*/;
recursive_mutex& operator=(const recursive_mutex&) /*= delete*/;
recursive_mutex()
{
#ifdef _WIN32
InitializeCriticalSection(&m_handle);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m_handle, &attr);
#endif
}
~recursive_mutex()
{
#ifdef _WIN32
DeleteCriticalSection(&m_handle);
#else
pthread_mutex_destroy(&m_handle);
#endif
}
void lock()
{
#ifdef _WIN32
EnterCriticalSection(&m_handle);
#else
pthread_mutex_lock(&m_handle);
#endif
}
void unlock()
{
#ifdef _WIN32
LeaveCriticalSection(&m_handle);
#else
pthread_mutex_unlock(&m_handle);
#endif
}
bool try_lock()
{
#ifdef _WIN32
return (0 != TryEnterCriticalSection(&m_handle));
#else
return !pthread_mutex_trylock(&m_handle);
#endif
}
native_handle_type native_handle()
{
return &m_handle;
}
private:
native_type m_handle;
};
#ifdef USE_SRWLOCKS
class mutex
{
#ifdef _WIN32
typedef SRWLOCK native_type;
#else
typedef pthread_mutex_t native_type;
#endif
public:
typedef native_type* native_handle_type;
mutex(const mutex&) /*= delete*/;
mutex& operator=(const mutex&) /*= delete*/;
mutex()
{
#ifdef _WIN32
InitializeSRWLock(&m_handle);
#else
pthread_mutex_init(&m_handle, NULL);
#endif
}
~mutex()
{
#ifdef _WIN32
#else
pthread_mutex_destroy(&m_handle);
#endif
}
void lock()
{
#ifdef _WIN32
AcquireSRWLockExclusive(&m_handle);
#else
pthread_mutex_lock(&m_handle);
#endif
}
void unlock()
{
#ifdef _WIN32
ReleaseSRWLockExclusive(&m_handle);
#else
pthread_mutex_unlock(&m_handle);
#endif
}
bool try_lock()
{
#ifdef _WIN32
return (0 != TryAcquireSRWLockExclusive(&m_handle));
#else
return !pthread_mutex_trylock(&m_handle);
#endif
}
native_handle_type native_handle()
{
return &m_handle;
}
private:
native_type m_handle;
};
#else
typedef recursive_mutex mutex; // just use CriticalSections
#endif
enum defer_lock_t { defer_lock };
enum try_to_lock_t { try_to_lock };
enum adopt_lock_t { adopt_lock };
template <class Mutex>
class lock_guard
{
public:
typedef Mutex mutex_type;
explicit lock_guard(mutex_type& m)
: pm(m)
{
m.lock();
}
lock_guard(mutex_type& m, adopt_lock_t)
: pm(m)
{
}
~lock_guard()
{
pm.unlock();
}
lock_guard(lock_guard const&) /*= delete*/;
lock_guard& operator=(lock_guard const&) /*= delete*/;
private:
mutex_type& pm;
};
template <class Mutex>
class unique_lock
{
public:
typedef Mutex mutex_type;
unique_lock()
: pm(NULL), owns(false)
{}
/*explicit*/ unique_lock(mutex_type& m)
: pm(&m), owns(true)
{
m.lock();
}
unique_lock(mutex_type& m, defer_lock_t)
: pm(&m), owns(false)
{}
unique_lock(mutex_type& m, try_to_lock_t)
: pm(&m), owns(m.try_lock())
{}
unique_lock(mutex_type& m, adopt_lock_t)
: pm(&m), owns(true)
{}
//template <class Clock, class Duration>
//unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
//template <class Rep, class Period>
//unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
~unique_lock()
{
if (owns_lock())
mutex()->unlock();
}
#ifdef USE_RVALUE_REFERENCES
unique_lock& operator=(const unique_lock&) /*= delete*/;
unique_lock& operator=(unique_lock&& other)
{
#else
unique_lock& operator=(const unique_lock& u)
{
// ugly const_cast to get around lack of rvalue references
unique_lock& other = const_cast<unique_lock&>(u);
#endif
swap(other);
return *this;
}
#ifdef USE_RVALUE_REFERENCES
unique_lock(const unique_lock&) /*= delete*/;
unique_lock(unique_lock&& other)
: pm(NULL), owns(false)
{
#else
unique_lock(const unique_lock& u)
: pm(NULL), owns(false)
{
// ugly const_cast to get around lack of rvalue references
unique_lock& other = const_cast<unique_lock&>(u);
#endif
swap(other);
}
void lock()
{
mutex()->lock();
owns = true;
}
bool try_lock()
{
owns = mutex()->try_lock();
return owns;
}
//template <class Rep, class Period>
//bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
//template <class Clock, class Duration>
//bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock()
{
mutex()->unlock();
owns = false;
}
void swap(unique_lock& u)
{
std::swap(pm, u.pm);
std::swap(owns, u.owns);
}
mutex_type* release()
{
return mutex();
pm = NULL;
owns = false;
}
bool owns_lock() const
{
return owns;
}
//explicit operator bool () const
//{
// return owns_lock();
//}
mutex_type* mutex() const
{
return pm;
}
private:
mutex_type* pm;
bool owns;
};
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y)
{
x.swap(y);
}
}
#endif
#endif

View File

@ -55,219 +55,49 @@ void SetCurrentThreadAffinity(u32 mask)
SetThreadAffinityMask(GetCurrentThread(), mask);
}
CriticalSection::CriticalSection(int spincount)
{
if (spincount)
{
if (!InitializeCriticalSectionAndSpinCount(&section, spincount))
ERROR_LOG(COMMON, "CriticalSection could not be initialized!\n%s", GetLastErrorMsg());
}
else
{
InitializeCriticalSection(&section);
}
}
// Supporting functions
void SleepCurrentThread(int ms)
{
Sleep(ms);
}
CriticalSection::~CriticalSection()
{
DeleteCriticalSection(&section);
}
void CriticalSection::Enter()
{
EnterCriticalSection(&section);
}
bool CriticalSection::TryEnter()
{
return TryEnterCriticalSection(&section) ? true : false;
}
void CriticalSection::Leave()
{
LeaveCriticalSection(&section);
}
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))
{
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)
{
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;
}
}
}
void SwitchCurrentThread()
{
SwitchToThread();
}
// Supporting functions
void SleepCurrentThread(int ms)
{
Sleep(ms);
}
// 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
void SwitchCurrentThread()
{
SwitchToThread();
}
typedef struct tagTHREADNAME_INFO
// This is implemented much nicer in upcoming msvc++, see:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
void SetCurrentThreadName(const char* szThreadName)
{
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
struct THREADNAME_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)
} info;
#pragma pack(pop)
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = -1; //dwThreadID;
info.dwFlags = 0;
__try
{
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;
#endif
info.dwThreadID = -1; //dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{}
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{}
}
#else // !WIN32, so must be POSIX threads
@ -293,151 +123,42 @@ void SetCurrentThreadAffinity(u32 mask)
SetThreadAffinity(pthread_self(), mask);
}
static pthread_key_t threadname_key;
static pthread_once_t threadname_key_once = PTHREAD_ONCE_INIT;
CriticalSection::CriticalSection(int spincount_unused)
{
pthread_mutex_init(&mutex, NULL);
}
CriticalSection::~CriticalSection()
{
pthread_mutex_destroy(&mutex);
}
void CriticalSection::Enter()
{
#ifdef DEBUG
int ret = pthread_mutex_lock(&mutex);
if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_lock(%p) failed: %s\n",
__FUNCTION__, &mutex, strerror(ret));
#else
pthread_mutex_lock(&mutex);
#endif
}
bool CriticalSection::TryEnter()
{
return(!pthread_mutex_trylock(&mutex));
}
void CriticalSection::Leave()
{
#ifdef DEBUG
int ret = pthread_mutex_unlock(&mutex);
if (ret) ERROR_LOG(COMMON, "%s: pthread_mutex_unlock(%p) failed: %s\n",
__FUNCTION__, &mutex, strerror(ret));
#else
pthread_mutex_unlock(&mutex);
#endif
}
static pthread_key_t threadname_key;
static pthread_once_t threadname_key_once = PTHREAD_ONCE_INIT;
void SleepCurrentThread(int ms)
{
usleep(1000 * ms);
}
void SleepCurrentThread(int ms)
{
usleep(1000 * ms);
}
void SwitchCurrentThread()
{
usleep(1000 * 1);
}
void SwitchCurrentThread()
{
usleep(1000 * 1);
}
static void FreeThreadName(void* threadname)
{
static void FreeThreadName(void* threadname)
{
free(threadname);
}
static void ThreadnameKeyAlloc()
{
pthread_key_create(&threadname_key, FreeThreadName);
}
void SetCurrentThreadName(const char* szThreadName)
{
pthread_once(&threadname_key_once, ThreadnameKeyAlloc);
void* threadname;
if ((threadname = pthread_getspecific(threadname_key)) != NULL)
free(threadname);
}
static void ThreadnameKeyAlloc()
{
pthread_key_create(&threadname_key, FreeThreadName);
}
pthread_setspecific(threadname_key, strdup(szThreadName));
void SetCurrentThreadName(const TCHAR* szThreadName)
{
pthread_once(&threadname_key_once, ThreadnameKeyAlloc);
INFO_LOG(COMMON, "%s(%s)\n", __FUNCTION__, szThreadName);
}
void* threadname;
if ((threadname = pthread_getspecific(threadname_key)) != NULL)
free(threadname);
pthread_setspecific(threadname_key, strdup(szThreadName));
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_);
}
pthread_mutex_unlock(&mutex_);
}
bool Event::Wait(const u32 timeout)
{
bool timedout = false;
struct timespec wait;
pthread_mutex_lock(&mutex_);
if (timeout != INFINITE)
{
memset(&wait, 0, sizeof(wait));
struct timeval now;
gettimeofday(&now, NULL);
wait.tv_nsec = (now.tv_usec + (timeout % 1000)) * 1000;
wait.tv_sec = now.tv_sec + (timeout / 1000);
}
while (!is_set_ && !timedout)
{
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;
}
#endif
} // namespace Common

View File

@ -19,6 +19,8 @@
#define _THREAD_H_
#include "StdThread.h"
#include "StdMutex.h"
#include "StdConditionVariable.h"
// Don't include common.h here as it will break LogManager
#include "CommonTypes.h"
@ -38,7 +40,6 @@
#include <sys/time.h>
#endif
namespace Common
{
@ -47,105 +48,70 @@ int CurrentThreadId();
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
class CriticalSection
class Event
{
public:
void Set()
{
#ifdef _WIN32
CRITICAL_SECTION section;
#else
#ifdef _POSIX_THREADS
pthread_mutex_t mutex;
#endif
#endif
public:
CriticalSection(int spincount = 1000);
~CriticalSection();
void Enter();
bool TryEnter();
void Leave();
};
#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;
};
#else
// 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);
#ifdef _WIN32
void MsgWait();
#else
void MsgWait() {Wait();}
#endif
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
#else
bool is_set_;
#ifdef _POSIX_THREADS
pthread_cond_t event_;
pthread_mutex_t mutex_;
#endif
#endif
};
void SleepCurrentThread(int ms);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
// 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
Sleep(0);
#elif defined(_M_IX86) || defined(_M_X64)
sleep(0);
#endif
m_condvar.notify_one();
}
void SetCurrentThreadName(const char *name);
void Wait()
{
std::unique_lock<std::mutex> lk(m_mutex);
m_condvar.wait(lk);
}
private:
std::condition_variable m_condvar;
std::mutex m_mutex;
};
// TODO: doesn't work on windows with (count > 2)
class Barrier
{
public:
Barrier(size_t count)
: m_count(count), m_waiting(0)
{}
// block until "count" threads call Wait()
bool Wait()
{
std::unique_lock<std::mutex> lk(m_mutex);
if (m_count == ++m_waiting)
{
m_waiting = 0;
m_condvar.notify_all();
return true;
}
else
{
m_condvar.wait(lk);
return false;
}
}
private:
std::condition_variable m_condvar;
std::mutex m_mutex;
const size_t m_count;
volatile size_t m_waiting;
};
void SleepCurrentThread(int ms);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
// 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()
{
std::this_thread::yield();
}
void SetCurrentThreadName(const char *name);
} // namespace Common