mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-11 11:33:01 +08:00
1402 lines
39 KiB
C
1402 lines
39 KiB
C
|
#ifndef THREADTOOLS_H
|
||
|
#define THREADTOOLS_H
|
||
|
|
||
|
#include <limits.h>
|
||
|
|
||
|
#include "platform.h"
|
||
|
#include "dbg.h"
|
||
|
#include "vcrmode.h"
|
||
|
|
||
|
#ifdef PLATFORM_WINDOWS_PC
|
||
|
#include <intrin.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef POSIX
|
||
|
#include <pthread.h>
|
||
|
#include <errno.h>
|
||
|
#define WAIT_OBJECT_0 0
|
||
|
#define WAIT_TIMEOUT 0x00000102
|
||
|
#define WAIT_FAILED -1
|
||
|
#define THREAD_PRIORITY_HIGHEST 2
|
||
|
#endif
|
||
|
|
||
|
#if defined( _WIN32 )
|
||
|
#pragma once
|
||
|
#pragma warning(push)
|
||
|
#pragma warning(disable:4251)
|
||
|
#endif
|
||
|
|
||
|
#ifndef _RETAIL
|
||
|
#define THREAD_MUTEX_TRACING_SUPPORTED
|
||
|
#if defined(_WIN32) && defined(_DEBUG)
|
||
|
#define THREAD_MUTEX_TRACING_ENABLED
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
typedef void* HANDLE;
|
||
|
#endif
|
||
|
|
||
|
const unsigned TT_INFINITE = 0xffffffff;
|
||
|
|
||
|
#ifndef NO_THREAD_LOCAL
|
||
|
|
||
|
#ifndef THREAD_LOCAL
|
||
|
#ifdef _WIN32
|
||
|
#define THREAD_LOCAL __declspec(thread)
|
||
|
#elif POSIX
|
||
|
#define THREAD_LOCAL __thread
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
typedef unsigned long ThreadId_t;
|
||
|
|
||
|
FORWARD_DECLARE_HANDLE(ThreadHandle_t);
|
||
|
typedef unsigned (*ThreadFunc_t)(void* pParam);
|
||
|
|
||
|
PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread(ThreadFunc_t, void* pParam, ThreadId_t* pID, unsigned stackSize = 0);
|
||
|
PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread(ThreadFunc_t, void* pParam, unsigned stackSize = 0);
|
||
|
PLATFORM_INTERFACE bool ReleaseThreadHandle(ThreadHandle_t);
|
||
|
|
||
|
|
||
|
PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0);
|
||
|
PLATFORM_INTERFACE uint ThreadGetCurrentId();
|
||
|
PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle();
|
||
|
PLATFORM_INTERFACE int ThreadGetPriority(ThreadHandle_t hThread = NULL);
|
||
|
PLATFORM_INTERFACE bool ThreadSetPriority(ThreadHandle_t hThread, int priority);
|
||
|
inline bool ThreadSetPriority(int priority) { return ThreadSetPriority(NULL, priority); }
|
||
|
PLATFORM_INTERFACE bool ThreadInMainThread();
|
||
|
PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread();
|
||
|
|
||
|
typedef int (*ThreadedLoadLibraryFunc_t)();
|
||
|
PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc(ThreadedLoadLibraryFunc_t func);
|
||
|
PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc();
|
||
|
|
||
|
#if defined( _WIN32 ) && !defined( _WIN64 ) && !defined( _X360 )
|
||
|
extern "C" unsigned long __declspec(dllimport) __stdcall GetCurrentThreadId();
|
||
|
#define ThreadGetCurrentId GetCurrentThreadId
|
||
|
#endif
|
||
|
|
||
|
inline void ThreadPause()
|
||
|
{
|
||
|
#if defined( PLATFORM_WINDOWS_PC )
|
||
|
_mm_pause();
|
||
|
#elif POSIX
|
||
|
__asm __volatile("pause");
|
||
|
#elif defined( _X360 )
|
||
|
#else
|
||
|
#error "implement me"
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
PLATFORM_INTERFACE bool ThreadJoin(ThreadHandle_t, unsigned timeout = TT_INFINITE);
|
||
|
PLATFORM_INTERFACE void ThreadDetach(ThreadHandle_t);
|
||
|
|
||
|
PLATFORM_INTERFACE void ThreadSetDebugName(ThreadId_t id, const char* pszName);
|
||
|
inline void ThreadSetDebugName(const char* pszName) { ThreadSetDebugName((ThreadId_t)-1, pszName); }
|
||
|
|
||
|
PLATFORM_INTERFACE void ThreadSetAffinity(ThreadHandle_t hThread, int nAffinityMask);
|
||
|
|
||
|
enum ThreadWaitResult_t
|
||
|
{
|
||
|
TW_FAILED = 0xffffffff,
|
||
|
TW_TIMEOUT = 0x00000102,
|
||
|
};
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
PLATFORM_INTERFACE int ThreadWaitForObjects(int nEvents, const HANDLE* pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE);
|
||
|
inline int ThreadWaitForObject(HANDLE handle, bool bWaitAll = true, unsigned timeout = TT_INFINITE) { return ThreadWaitForObjects(1, &handle, bWaitAll, timeout); }
|
||
|
#endif
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
#define NOINLINE
|
||
|
#elif POSIX
|
||
|
#define NOINLINE __attribute__ ((noinline))
|
||
|
#endif
|
||
|
|
||
|
#if defined( _X360 ) || defined( _PS3 )
|
||
|
#define ThreadMemoryBarrier() __lwsync()
|
||
|
|
||
|
#elif defined(_MSC_VER)
|
||
|
#if _MSC_VER < 1500
|
||
|
#pragma intrinsic(_ReadWriteBarrier)
|
||
|
#endif
|
||
|
#define ThreadMemoryBarrier() _ReadWriteBarrier()
|
||
|
#elif defined(GNUC)
|
||
|
#define ThreadMemoryBarrier() asm volatile("" ::: "memory")
|
||
|
#else
|
||
|
#error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering
|
||
|
#endif
|
||
|
|
||
|
#if defined(_WIN32) && !defined(_X360)
|
||
|
#if ( _MSC_VER >= 1310 )
|
||
|
#define USE_INTRINSIC_INTERLOCKED
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef USE_INTRINSIC_INTERLOCKED
|
||
|
extern "C"
|
||
|
{
|
||
|
long __cdecl _InterlockedIncrement(volatile long*);
|
||
|
long __cdecl _InterlockedDecrement(volatile long*);
|
||
|
long __cdecl _InterlockedExchange(volatile long*, long);
|
||
|
long __cdecl _InterlockedExchangeAdd(volatile long*, long);
|
||
|
long __cdecl _InterlockedCompareExchange(volatile long*, long, long);
|
||
|
}
|
||
|
|
||
|
#pragma intrinsic( _InterlockedCompareExchange )
|
||
|
#pragma intrinsic( _InterlockedDecrement )
|
||
|
#pragma intrinsic( _InterlockedExchange )
|
||
|
#pragma intrinsic( _InterlockedExchangeAdd )
|
||
|
#pragma intrinsic( _InterlockedIncrement )
|
||
|
|
||
|
inline long ThreadInterlockedIncrement(long volatile* p) { Assert((size_t)p % 4 == 0); return _InterlockedIncrement(p); }
|
||
|
inline long ThreadInterlockedDecrement(long volatile* p) { Assert((size_t)p % 4 == 0); return _InterlockedDecrement(p); }
|
||
|
inline long ThreadInterlockedExchange(long volatile* p, long value) { Assert((size_t)p % 4 == 0); return _InterlockedExchange(p, value); }
|
||
|
inline long ThreadInterlockedExchangeAdd(long volatile* p, long value) { Assert((size_t)p % 4 == 0); return _InterlockedExchangeAdd(p, value); }
|
||
|
inline long ThreadInterlockedCompareExchange(long volatile* p, long value, long comperand) { Assert((size_t)p % 4 == 0); return _InterlockedCompareExchange(p, value, comperand); }
|
||
|
inline bool ThreadInterlockedAssignIf(long volatile* p, long value, long comperand) { Assert((size_t)p % 4 == 0); return (_InterlockedCompareExchange(p, value, comperand) == comperand); }
|
||
|
#else
|
||
|
PLATFORM_INTERFACE long ThreadInterlockedIncrement(long volatile*);
|
||
|
PLATFORM_INTERFACE long ThreadInterlockedDecrement(long volatile*);
|
||
|
PLATFORM_INTERFACE long ThreadInterlockedExchange(long volatile*, long value);
|
||
|
PLATFORM_INTERFACE long ThreadInterlockedExchangeAdd(long volatile*, long value);
|
||
|
PLATFORM_INTERFACE long ThreadInterlockedCompareExchange(long volatile*, long value, long comperand);
|
||
|
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf(long volatile*, long value, long comperand);
|
||
|
#endif
|
||
|
|
||
|
inline unsigned ThreadInterlockedExchangeSubtract(long volatile* p, long value) { return ThreadInterlockedExchangeAdd((long volatile*)p, -value); }
|
||
|
|
||
|
#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( _WIN64 )
|
||
|
#define TIPTR()
|
||
|
inline void* ThreadInterlockedExchangePointer(void* volatile* p, void* value) { return (void*)_InterlockedExchange(reinterpret_cast<long volatile*>(p), reinterpret_cast<long>(value)); }
|
||
|
inline void* ThreadInterlockedCompareExchangePointer(void* volatile* p, void* value, void* comperand) { return (void*)_InterlockedCompareExchange(reinterpret_cast<long volatile*>(p), reinterpret_cast<long>(value), reinterpret_cast<long>(comperand)); }
|
||
|
inline bool ThreadInterlockedAssignPointerIf(void* volatile* p, void* value, void* comperand) { return (_InterlockedCompareExchange(reinterpret_cast<long volatile*>(p), reinterpret_cast<long>(value), reinterpret_cast<long>(comperand)) == reinterpret_cast<long>(comperand)); }
|
||
|
#else
|
||
|
PLATFORM_INTERFACE void* ThreadInterlockedExchangePointer(void* volatile*, void* value) NOINLINE;
|
||
|
PLATFORM_INTERFACE void* ThreadInterlockedCompareExchangePointer(void* volatile*, void* value, void* comperand) NOINLINE;
|
||
|
PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf(void* volatile*, void* value, void* comperand) NOINLINE;
|
||
|
#endif
|
||
|
|
||
|
inline void const* ThreadInterlockedExchangePointerToConst(void const* volatile* p, void const* value) { return ThreadInterlockedExchangePointer(const_cast <void* volatile*> (p), const_cast <void*> (value)); }
|
||
|
inline void const* ThreadInterlockedCompareExchangePointerToConst(void const* volatile* p, void const* value, void const* comperand) { return ThreadInterlockedCompareExchangePointer(const_cast <void* volatile*> (p), const_cast <void*> (value), const_cast <void*> (comperand)); }
|
||
|
inline bool ThreadInterlockedAssignPointerToConstIf(void const* volatile* p, void const* value, void const* comperand) { return ThreadInterlockedAssignPointerIf(const_cast <void* volatile*> (p), const_cast <void*> (value), const_cast <void*> (comperand)); }
|
||
|
|
||
|
#if defined( PLATFORM_64BITS )
|
||
|
#if defined (_WIN32)
|
||
|
typedef __m128i int128;
|
||
|
inline int128 int128_zero() { return _mm_setzero_si128(); }
|
||
|
#else
|
||
|
typedef __int128_t int128;
|
||
|
#define int128_zero() 0
|
||
|
#endif
|
||
|
|
||
|
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128(volatile int128* pDest, const int128& value, const int128& comperand) NOINLINE;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64(int64 volatile*) NOINLINE;
|
||
|
PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64(int64 volatile*) NOINLINE;
|
||
|
PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64(int64 volatile*, int64 value, int64 comperand) NOINLINE;
|
||
|
PLATFORM_INTERFACE int64 ThreadInterlockedExchange64(int64 volatile*, int64 value) NOINLINE;
|
||
|
PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64(int64 volatile*, int64 value) NOINLINE;
|
||
|
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64* pDest, int64 value, int64 comperand) NOINLINE;
|
||
|
|
||
|
inline unsigned ThreadInterlockedExchangeSubtract(unsigned volatile* p, unsigned value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); }
|
||
|
inline unsigned ThreadInterlockedIncrement(unsigned volatile* p) { return ThreadInterlockedIncrement((long volatile*)p); }
|
||
|
inline unsigned ThreadInterlockedDecrement(unsigned volatile* p) { return ThreadInterlockedDecrement((long volatile*)p); }
|
||
|
inline unsigned ThreadInterlockedExchange(unsigned volatile* p, unsigned value) { return ThreadInterlockedExchange((long volatile*)p, value); }
|
||
|
inline unsigned ThreadInterlockedExchangeAdd(unsigned volatile* p, unsigned value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); }
|
||
|
inline unsigned ThreadInterlockedCompareExchange(unsigned volatile* p, unsigned value, unsigned comperand) { return ThreadInterlockedCompareExchange((long volatile*)p, value, comperand); }
|
||
|
inline bool ThreadInterlockedAssignIf(unsigned volatile* p, unsigned value, unsigned comperand) { return ThreadInterlockedAssignIf((long volatile*)p, value, comperand); }
|
||
|
|
||
|
inline int ThreadInterlockedExchangeSubtract(int volatile* p, int value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); }
|
||
|
inline int ThreadInterlockedIncrement(int volatile* p) { return ThreadInterlockedIncrement((long volatile*)p); }
|
||
|
inline int ThreadInterlockedDecrement(int volatile* p) { return ThreadInterlockedDecrement((long volatile*)p); }
|
||
|
inline int ThreadInterlockedExchange(int volatile* p, int value) { return ThreadInterlockedExchange((long volatile*)p, value); }
|
||
|
inline int ThreadInterlockedExchangeAdd(int volatile* p, int value) { return ThreadInterlockedExchangeAdd((long volatile*)p, value); }
|
||
|
inline int ThreadInterlockedCompareExchange(int volatile* p, int value, int comperand) { return ThreadInterlockedCompareExchange((long volatile*)p, value, comperand); }
|
||
|
inline bool ThreadInterlockedAssignIf(int volatile* p, int value, int comperand) { return ThreadInterlockedAssignIf((long volatile*)p, value, comperand); }
|
||
|
|
||
|
#if defined(_WIN32) && defined(THREAD_PROFILER)
|
||
|
PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void* p);
|
||
|
PLATFORM_INTERFACE void ThreadNotifySyncCancel(void* p);
|
||
|
PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void* p);
|
||
|
PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void* p);
|
||
|
#else
|
||
|
#define ThreadNotifySyncPrepare(p) ((void)0)
|
||
|
#define ThreadNotifySyncCancel(p) ((void)0)
|
||
|
#define ThreadNotifySyncAcquired(p) ((void)0)
|
||
|
#define ThreadNotifySyncReleasing(p) ((void)0)
|
||
|
#endif
|
||
|
|
||
|
#ifndef NO_THREAD_LOCAL
|
||
|
|
||
|
#if defined(_LINUX) && !defined(OSX)
|
||
|
#define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1
|
||
|
#define CTHREADLOCALINTEGER( typ ) __thread int
|
||
|
#define CTHREADLOCALINT __thread int
|
||
|
#define CTHREADLOCALPTR( typ ) __thread typ *
|
||
|
#define CTHREADLOCAL( typ ) __thread typ
|
||
|
#define GETLOCAL( x ) ( x )
|
||
|
#endif
|
||
|
|
||
|
#if defined(WIN32) || defined(OSX)
|
||
|
#ifndef __AFXTLS_H__
|
||
|
#define CTHREADLOCALINT CThreadLocalInt<int>
|
||
|
#define CTHREADLOCALINTEGER( typ ) CThreadLocalInt<typ>
|
||
|
#define CTHREADLOCALPTR( typ ) CThreadLocalPtr<typ>
|
||
|
#define CTHREADLOCAL( typ ) CThreadLocal<typ>
|
||
|
#define GETLOCAL( x ) ( x.Get() )
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifndef __AFXTLS_H__
|
||
|
#ifndef NO_THREAD_LOCAL
|
||
|
|
||
|
class PLATFORM_CLASS CThreadLocalBase
|
||
|
{
|
||
|
public:
|
||
|
CThreadLocalBase();
|
||
|
~CThreadLocalBase();
|
||
|
|
||
|
void* Get() const;
|
||
|
void Set(void*);
|
||
|
|
||
|
private:
|
||
|
#ifdef _WIN32
|
||
|
uint32 m_index;
|
||
|
#elif POSIX
|
||
|
pthread_key_t m_index;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
#ifndef __AFXTLS_H__
|
||
|
|
||
|
template <class T>
|
||
|
class CThreadLocal : public CThreadLocalBase
|
||
|
{
|
||
|
public:
|
||
|
CThreadLocal()
|
||
|
{
|
||
|
COMPILE_TIME_ASSERT(sizeof(T) == sizeof(void*));
|
||
|
}
|
||
|
|
||
|
T Get() const
|
||
|
{
|
||
|
return reinterpret_cast<T>(CThreadLocalBase::Get());
|
||
|
}
|
||
|
|
||
|
void Set(T val)
|
||
|
{
|
||
|
CThreadLocalBase::Set(reinterpret_cast<void*>(val));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
template <class T = intp>
|
||
|
class CThreadLocalInt : public CThreadLocal<T>
|
||
|
{
|
||
|
public:
|
||
|
CThreadLocalInt()
|
||
|
{
|
||
|
COMPILE_TIME_ASSERT(sizeof(T) >= sizeof(int));
|
||
|
}
|
||
|
|
||
|
operator int() const { return (int)this->Get(); }
|
||
|
int operator=(int i) { this->Set((intp)i); return i; }
|
||
|
|
||
|
int operator++() { T i = this->Get(); this->Set(++i); return (int)i; }
|
||
|
int operator++(int) { T i = this->Get(); this->Set(i + 1); return (int)i; }
|
||
|
|
||
|
int operator--() { T i = this->Get(); this->Set(--i); return (int)i; }
|
||
|
int operator--(int) { T i = this->Get(); this->Set(i - 1); return (int)i; }
|
||
|
};
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
class CThreadLocalPtr : private CThreadLocalBase
|
||
|
{
|
||
|
public:
|
||
|
CThreadLocalPtr() {}
|
||
|
|
||
|
operator const void* () const { return (T*)Get(); }
|
||
|
operator void* () { return (T*)Get(); }
|
||
|
|
||
|
operator const T* () const { return (T*)Get(); }
|
||
|
operator const T* () { return (T*)Get(); }
|
||
|
operator T* () { return (T*)Get(); }
|
||
|
|
||
|
int operator=(int i) { AssertMsg(i == 0, "Only NULL allowed on integer assign"); Set(NULL); return 0; }
|
||
|
T* operator=(T* p) { Set(p); return p; }
|
||
|
|
||
|
bool operator !() const { return (!Get()); }
|
||
|
bool operator!=(int i) const { AssertMsg(i == 0, "Only NULL allowed on integer compare"); return (Get() != NULL); }
|
||
|
bool operator==(int i) const { AssertMsg(i == 0, "Only NULL allowed on integer compare"); return (Get() == NULL); }
|
||
|
bool operator==(const void* p) const { return (Get() == p); }
|
||
|
bool operator!=(const void* p) const { return (Get() != p); }
|
||
|
bool operator==(const T* p) const { return operator==((void*)p); }
|
||
|
bool operator!=(const T* p) const { return operator!=((void*)p); }
|
||
|
|
||
|
T* operator->() { return (T*)Get(); }
|
||
|
T& operator *() { return *((T*)Get()); }
|
||
|
|
||
|
const T* operator->() const { return (T*)Get(); }
|
||
|
const T& operator *() const { return *((T*)Get()); }
|
||
|
|
||
|
const T& operator[](int i) const { return *((T*)Get() + i); }
|
||
|
T& operator[](int i) { return *((T*)Get() + i); }
|
||
|
|
||
|
private:
|
||
|
CThreadLocalPtr(T* pFrom);
|
||
|
CThreadLocalPtr(const CThreadLocalPtr<T>& from);
|
||
|
T** operator &();
|
||
|
T* const* operator &() const;
|
||
|
void operator=(const CThreadLocalPtr<T>& from);
|
||
|
bool operator==(const CThreadLocalPtr<T>& p) const;
|
||
|
bool operator!=(const CThreadLocalPtr<T>& p) const;
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
template <typename T>
|
||
|
class CInterlockedIntT
|
||
|
{
|
||
|
public:
|
||
|
CInterlockedIntT() : m_value(0) { COMPILE_TIME_ASSERT(sizeof(T) == sizeof(long)); }
|
||
|
CInterlockedIntT(T value) : m_value(value) {}
|
||
|
|
||
|
T GetRaw() const { return m_value; }
|
||
|
|
||
|
operator T() const { return m_value; }
|
||
|
|
||
|
bool operator!() const { return (m_value == 0); }
|
||
|
bool operator==(T rhs) const { return (m_value == rhs); }
|
||
|
bool operator!=(T rhs) const { return (m_value != rhs); }
|
||
|
|
||
|
T operator++() { return (T)ThreadInterlockedIncrement((long*)&m_value); }
|
||
|
T operator++(int) { return operator++() - 1; }
|
||
|
|
||
|
T operator--() { return (T)ThreadInterlockedDecrement((long*)&m_value); }
|
||
|
T operator--(int) { return operator--() + 1; }
|
||
|
|
||
|
bool AssignIf(T conditionValue, T newValue) { return ThreadInterlockedAssignIf((long*)&m_value, (long)newValue, (long)conditionValue); }
|
||
|
|
||
|
T operator=(T newValue) { ThreadInterlockedExchange((long*)&m_value, newValue); return m_value; }
|
||
|
|
||
|
void operator+=(T add) { ThreadInterlockedExchangeAdd((long*)&m_value, (long)add); }
|
||
|
void operator-=(T subtract) { operator+=(-subtract); }
|
||
|
void operator*=(T multiplier) {
|
||
|
T original, result;
|
||
|
do
|
||
|
{
|
||
|
original = m_value;
|
||
|
result = original * multiplier;
|
||
|
} while (!AssignIf(original, result));
|
||
|
}
|
||
|
void operator/=(T divisor) {
|
||
|
T original, result;
|
||
|
do
|
||
|
{
|
||
|
original = m_value;
|
||
|
result = original / divisor;
|
||
|
} while (!AssignIf(original, result));
|
||
|
}
|
||
|
|
||
|
T operator+(T rhs) const { return m_value + rhs; }
|
||
|
T operator-(T rhs) const { return m_value - rhs; }
|
||
|
|
||
|
private:
|
||
|
volatile T m_value;
|
||
|
};
|
||
|
|
||
|
typedef CInterlockedIntT<int> CInterlockedInt;
|
||
|
typedef CInterlockedIntT<unsigned> CInterlockedUInt;
|
||
|
|
||
|
template <typename T>
|
||
|
class CInterlockedPtr
|
||
|
{
|
||
|
public:
|
||
|
CInterlockedPtr() : m_value(0) {}
|
||
|
CInterlockedPtr(T* value) : m_value(value) {}
|
||
|
|
||
|
operator T* () const { return m_value; }
|
||
|
|
||
|
bool operator!() const { return (m_value == 0); }
|
||
|
bool operator==(T* rhs) const { return (m_value == rhs); }
|
||
|
bool operator!=(T* rhs) const { return (m_value != rhs); }
|
||
|
|
||
|
#if defined( PLATFORM_64BITS )
|
||
|
T* operator++() { return ((T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, sizeof(T))) + 1; }
|
||
|
T* operator++(int) { return (T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, sizeof(T)); }
|
||
|
|
||
|
T* operator--() { return ((T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, -sizeof(T))) - 1; }
|
||
|
T* operator--(int) { return (T*)ThreadInterlockedExchangeAdd64((int64*)&m_value, -sizeof(T)); }
|
||
|
|
||
|
bool AssignIf(T* conditionValue, T* newValue) { return ThreadInterlockedAssignPointerToConstIf((void const**)&m_value, (void const*)newValue, (void const*)conditionValue); }
|
||
|
|
||
|
T* operator=(T* newValue) { ThreadInterlockedExchangePointerToConst((void const**)&m_value, (void const*)newValue); return newValue; }
|
||
|
|
||
|
void operator+=(int add) { ThreadInterlockedExchangeAdd64((int64*)&m_value, add * sizeof(T)); }
|
||
|
#else
|
||
|
T* operator++() { return ((T*)ThreadInterlockedExchangeAdd((long*)&m_value, sizeof(T))) + 1; }
|
||
|
T* operator++(int) { return (T*)ThreadInterlockedExchangeAdd((long*)&m_value, sizeof(T)); }
|
||
|
|
||
|
T* operator--() { return ((T*)ThreadInterlockedExchangeAdd((long*)&m_value, -sizeof(T))) - 1; }
|
||
|
T* operator--(int) { return (T*)ThreadInterlockedExchangeAdd((long*)&m_value, -sizeof(T)); }
|
||
|
|
||
|
bool AssignIf(T* conditionValue, T* newValue) { return ThreadInterlockedAssignPointerToConstIf((void const**)&m_value, (void const*)newValue, (void const*)conditionValue); }
|
||
|
|
||
|
T* operator=(T* newValue) { ThreadInterlockedExchangePointerToConst((void const**)&m_value, (void const*)newValue); return newValue; }
|
||
|
|
||
|
void operator+=(int add) { ThreadInterlockedExchangeAdd((long*)&m_value, add * sizeof(T)); }
|
||
|
#endif
|
||
|
|
||
|
void operator-=(int subtract) { operator+=(-subtract); }
|
||
|
|
||
|
T* operator+(int rhs) const { return m_value + rhs; }
|
||
|
T* operator-(int rhs) const { return m_value - rhs; }
|
||
|
T* operator+(unsigned rhs) const { return m_value + rhs; }
|
||
|
T* operator-(unsigned rhs) const { return m_value - rhs; }
|
||
|
size_t operator-(T* p) const { return m_value - p; }
|
||
|
size_t operator-(const CInterlockedPtr<T>& p) const { return m_value - p.m_value; }
|
||
|
|
||
|
private:
|
||
|
T* volatile m_value;
|
||
|
};
|
||
|
|
||
|
class PLATFORM_CLASS CThreadMutex
|
||
|
{
|
||
|
public:
|
||
|
CThreadMutex();
|
||
|
~CThreadMutex();
|
||
|
|
||
|
void Lock();
|
||
|
void Lock() const { (const_cast<CThreadMutex*>(this))->Lock(); }
|
||
|
void Unlock();
|
||
|
void Unlock() const { (const_cast<CThreadMutex*>(this))->Unlock(); }
|
||
|
|
||
|
bool TryLock();
|
||
|
bool TryLock() const { return (const_cast<CThreadMutex*>(this))->TryLock(); }
|
||
|
|
||
|
bool AssertOwnedByCurrentThread();
|
||
|
|
||
|
void SetTrace(bool);
|
||
|
|
||
|
private:
|
||
|
CThreadMutex(const CThreadMutex&);
|
||
|
CThreadMutex& operator=(const CThreadMutex&);
|
||
|
|
||
|
#if defined( _WIN32 )
|
||
|
#ifdef _WIN64
|
||
|
#define TT_SIZEOF_CRITICALSECTION 40
|
||
|
#else
|
||
|
#ifndef _X360
|
||
|
#define TT_SIZEOF_CRITICALSECTION 24
|
||
|
#else
|
||
|
#define TT_SIZEOF_CRITICALSECTION 28
|
||
|
#endif
|
||
|
#endif
|
||
|
byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION];
|
||
|
#elif defined(POSIX)
|
||
|
pthread_mutex_t m_Mutex;
|
||
|
pthread_mutexattr_t m_Attr;
|
||
|
#else
|
||
|
#error
|
||
|
#endif
|
||
|
|
||
|
#ifdef THREAD_MUTEX_TRACING_SUPPORTED
|
||
|
uint m_currentOwnerID;
|
||
|
uint16 m_lockCount;
|
||
|
bool m_bTrace;
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
#if !defined(THREAD_PROFILER)
|
||
|
|
||
|
class CThreadFastMutex
|
||
|
{
|
||
|
public:
|
||
|
CThreadFastMutex()
|
||
|
: m_ownerID(0),
|
||
|
m_depth(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
FORCEINLINE bool TryLockInline(const uint32 threadId) volatile
|
||
|
{
|
||
|
if (threadId != m_ownerID && !ThreadInterlockedAssignIf((volatile long*)&m_ownerID, (long)threadId, 0))
|
||
|
return false;
|
||
|
|
||
|
ThreadMemoryBarrier();
|
||
|
++m_depth;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool TryLock(const uint32 threadId) volatile
|
||
|
{
|
||
|
return TryLockInline(threadId);
|
||
|
}
|
||
|
|
||
|
PLATFORM_CLASS void Lock(const uint32 threadId, unsigned nSpinSleepTime) volatile;
|
||
|
|
||
|
public:
|
||
|
bool TryLock() volatile
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
if (m_depth == INT_MAX)
|
||
|
DebuggerBreak();
|
||
|
|
||
|
if (m_depth < 0)
|
||
|
DebuggerBreak();
|
||
|
#endif
|
||
|
return TryLockInline(ThreadGetCurrentId());
|
||
|
}
|
||
|
|
||
|
#ifndef _DEBUG
|
||
|
FORCEINLINE
|
||
|
#endif
|
||
|
void Lock(unsigned int nSpinSleepTime = 0) volatile
|
||
|
{
|
||
|
const uint32 threadId = ThreadGetCurrentId();
|
||
|
|
||
|
if (!TryLockInline(threadId))
|
||
|
{
|
||
|
ThreadPause();
|
||
|
Lock(threadId, nSpinSleepTime);
|
||
|
}
|
||
|
#ifdef _DEBUG
|
||
|
if (m_ownerID != ThreadGetCurrentId())
|
||
|
DebuggerBreak();
|
||
|
|
||
|
if (m_depth == INT_MAX)
|
||
|
DebuggerBreak();
|
||
|
|
||
|
if (m_depth < 0)
|
||
|
DebuggerBreak();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifndef _DEBUG
|
||
|
FORCEINLINE
|
||
|
#endif
|
||
|
void Unlock() volatile
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
if (m_ownerID != ThreadGetCurrentId())
|
||
|
DebuggerBreak();
|
||
|
|
||
|
if (m_depth <= 0)
|
||
|
DebuggerBreak();
|
||
|
#endif
|
||
|
|
||
|
--m_depth;
|
||
|
if (!m_depth)
|
||
|
{
|
||
|
ThreadMemoryBarrier();
|
||
|
ThreadInterlockedExchange(&m_ownerID, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef WIN32
|
||
|
bool TryLock() const volatile { return (const_cast<CThreadFastMutex*>(this))->TryLock(); }
|
||
|
void Lock(unsigned nSpinSleepTime = 1) const volatile { (const_cast<CThreadFastMutex*>(this))->Lock(nSpinSleepTime); }
|
||
|
void Unlock() const volatile { (const_cast<CThreadFastMutex*>(this))->Unlock(); }
|
||
|
#endif
|
||
|
bool AssertOwnedByCurrentThread() { return true; }
|
||
|
void SetTrace(bool) {}
|
||
|
|
||
|
uint32 GetOwnerId() const { return m_ownerID; }
|
||
|
int GetDepth() const { return m_depth; }
|
||
|
private:
|
||
|
volatile uint32 m_ownerID;
|
||
|
int m_depth;
|
||
|
};
|
||
|
|
||
|
class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex
|
||
|
{
|
||
|
public:
|
||
|
CAlignedThreadFastMutex()
|
||
|
{
|
||
|
Assert((size_t)this % 128 == 0 && sizeof(*this) == 128);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
uint8 pad[128 - sizeof(CThreadFastMutex)];
|
||
|
} ALIGN128_POST;
|
||
|
|
||
|
#else
|
||
|
typedef CThreadMutex CThreadFastMutex;
|
||
|
#endif
|
||
|
|
||
|
class CThreadNullMutex
|
||
|
{
|
||
|
public:
|
||
|
static void Lock() {}
|
||
|
static void Unlock() {}
|
||
|
|
||
|
static bool TryLock() { return true; }
|
||
|
static bool AssertOwnedByCurrentThread() { return true; }
|
||
|
static void SetTrace(bool b) {}
|
||
|
|
||
|
static uint32 GetOwnerId() { return 0; }
|
||
|
static int GetDepth() { return 0; }
|
||
|
};
|
||
|
|
||
|
template <class BaseClass, bool* pCondition>
|
||
|
class CThreadConditionalMutex : public BaseClass
|
||
|
{
|
||
|
public:
|
||
|
void Lock() { if (*pCondition) BaseClass::Lock(); }
|
||
|
void Lock() const { if (*pCondition) BaseClass::Lock(); }
|
||
|
void Unlock() { if (*pCondition) BaseClass::Unlock(); }
|
||
|
void Unlock() const { if (*pCondition) BaseClass::Unlock(); }
|
||
|
|
||
|
bool TryLock() { if (*pCondition) return BaseClass::TryLock(); else return true; }
|
||
|
bool TryLock() const { if (*pCondition) return BaseClass::TryLock(); else return true; }
|
||
|
bool AssertOwnedByCurrentThread() { if (*pCondition) return BaseClass::AssertOwnedByCurrentThread(); else return true; }
|
||
|
void SetTrace(bool b) { if (*pCondition) BaseClass::SetTrace(b); }
|
||
|
};
|
||
|
|
||
|
template <class BaseClass>
|
||
|
class CThreadTerminalMutex : public BaseClass
|
||
|
{
|
||
|
public:
|
||
|
bool TryLock() { if (!BaseClass::TryLock()) { DebuggerBreak(); return false; } return true; }
|
||
|
bool TryLock() const { if (!BaseClass::TryLock()) { DebuggerBreak(); return false; } return true; }
|
||
|
void Lock() { if (!TryLock()) BaseClass::Lock(); }
|
||
|
void Lock() const { if (!TryLock()) BaseClass::Lock(); }
|
||
|
|
||
|
};
|
||
|
|
||
|
template <class MUTEX_TYPE = CThreadMutex>
|
||
|
class CAutoLockT
|
||
|
{
|
||
|
public:
|
||
|
FORCEINLINE CAutoLockT(MUTEX_TYPE& lock)
|
||
|
: m_lock(lock)
|
||
|
{
|
||
|
m_lock.Lock();
|
||
|
}
|
||
|
|
||
|
FORCEINLINE CAutoLockT(const MUTEX_TYPE& lock)
|
||
|
: m_lock(const_cast<MUTEX_TYPE&>(lock))
|
||
|
{
|
||
|
m_lock.Lock();
|
||
|
}
|
||
|
|
||
|
FORCEINLINE ~CAutoLockT()
|
||
|
{
|
||
|
m_lock.Unlock();
|
||
|
}
|
||
|
|
||
|
|
||
|
private:
|
||
|
MUTEX_TYPE& m_lock;
|
||
|
|
||
|
CAutoLockT<MUTEX_TYPE>(const CAutoLockT<MUTEX_TYPE>&);
|
||
|
CAutoLockT<MUTEX_TYPE>& operator=(const CAutoLockT<MUTEX_TYPE>&);
|
||
|
};
|
||
|
|
||
|
typedef CAutoLockT<CThreadMutex> CAutoLock;
|
||
|
|
||
|
template <int size> struct CAutoLockTypeDeducer {};
|
||
|
template <> struct CAutoLockTypeDeducer<sizeof(CThreadMutex)> { typedef CThreadMutex Type_t; };
|
||
|
template <> struct CAutoLockTypeDeducer<sizeof(CThreadNullMutex)> { typedef CThreadNullMutex Type_t; };
|
||
|
#if !defined(THREAD_PROFILER)
|
||
|
template <> struct CAutoLockTypeDeducer<sizeof(CThreadFastMutex)> { typedef CThreadFastMutex Type_t; };
|
||
|
template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; };
|
||
|
#endif
|
||
|
|
||
|
#define AUTO_LOCK_( type, mutex ) \
|
||
|
CAutoLockT< type > UNIQUE_ID( static_cast<const type &>( mutex ) )
|
||
|
|
||
|
#if defined(GNUC)
|
||
|
|
||
|
template<typename T> T strip_cv_quals_for_mutex(T&);
|
||
|
template<typename T> T strip_cv_quals_for_mutex(const T&);
|
||
|
template<typename T> T strip_cv_quals_for_mutex(volatile T&);
|
||
|
template<typename T> T strip_cv_quals_for_mutex(const volatile T&);
|
||
|
|
||
|
#define AUTO_LOCK( mutex ) \
|
||
|
AUTO_LOCK_( typeof(::strip_cv_quals_for_mutex(mutex)), mutex )
|
||
|
|
||
|
#else
|
||
|
|
||
|
#define AUTO_LOCK( mutex ) \
|
||
|
AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex )
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#define AUTO_LOCK_FM( mutex ) \
|
||
|
AUTO_LOCK_( CThreadFastMutex, mutex )
|
||
|
|
||
|
#define LOCAL_THREAD_LOCK_( tag ) \
|
||
|
; \
|
||
|
static CThreadFastMutex autoMutex_##tag; \
|
||
|
AUTO_LOCK( autoMutex_##tag )
|
||
|
|
||
|
#define LOCAL_THREAD_LOCK() \
|
||
|
LOCAL_THREAD_LOCK_(_)
|
||
|
|
||
|
class PLATFORM_CLASS CThreadSyncObject
|
||
|
{
|
||
|
public:
|
||
|
~CThreadSyncObject();
|
||
|
|
||
|
bool operator!() const;
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
operator HANDLE() { return GetHandle(); }
|
||
|
const HANDLE GetHandle() const { return m_hSyncObject; }
|
||
|
#endif
|
||
|
bool Wait(uint32 dwTimeout = TT_INFINITE);
|
||
|
|
||
|
protected:
|
||
|
CThreadSyncObject();
|
||
|
void AssertUseable();
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
HANDLE m_hSyncObject;
|
||
|
bool m_bCreatedHandle;
|
||
|
#elif defined(POSIX)
|
||
|
pthread_mutex_t m_Mutex;
|
||
|
pthread_cond_t m_Condition;
|
||
|
bool m_bInitalized;
|
||
|
int m_cSet;
|
||
|
bool m_bManualReset;
|
||
|
bool m_bWakeForEvent;
|
||
|
#else
|
||
|
#error "Implement me"
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
CThreadSyncObject(const CThreadSyncObject&);
|
||
|
CThreadSyncObject& operator=(const CThreadSyncObject&);
|
||
|
};
|
||
|
|
||
|
|
||
|
#if defined( _WIN32 )
|
||
|
|
||
|
class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject
|
||
|
{
|
||
|
public:
|
||
|
CThreadSemaphore(long initialValue, long maxValue);
|
||
|
|
||
|
bool Release(long releaseCount = 1, long* pPreviousCount = NULL);
|
||
|
|
||
|
private:
|
||
|
CThreadSemaphore(const CThreadSemaphore&);
|
||
|
CThreadSemaphore& operator=(const CThreadSemaphore&);
|
||
|
};
|
||
|
|
||
|
|
||
|
class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject
|
||
|
{
|
||
|
public:
|
||
|
CThreadFullMutex(bool bEstablishInitialOwnership = false, const char* pszName = NULL);
|
||
|
|
||
|
bool Release();
|
||
|
|
||
|
void Lock() { Wait(); }
|
||
|
void Lock(unsigned timeout) { Wait(timeout); }
|
||
|
void Unlock() { Release(); }
|
||
|
bool AssertOwnedByCurrentThread() { return true; }
|
||
|
void SetTrace(bool) {}
|
||
|
|
||
|
private:
|
||
|
CThreadFullMutex(const CThreadFullMutex&);
|
||
|
CThreadFullMutex& operator=(const CThreadFullMutex&);
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
|
||
|
class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject
|
||
|
{
|
||
|
public:
|
||
|
CThreadEvent(bool fManualReset = false);
|
||
|
#ifdef WIN32
|
||
|
CThreadEvent(HANDLE hHandle);
|
||
|
#endif
|
||
|
bool Set();
|
||
|
|
||
|
bool Reset();
|
||
|
|
||
|
bool Check();
|
||
|
|
||
|
bool Wait(uint32 dwTimeout = TT_INFINITE);
|
||
|
|
||
|
private:
|
||
|
CThreadEvent(const CThreadEvent&);
|
||
|
CThreadEvent& operator=(const CThreadEvent&);
|
||
|
};
|
||
|
|
||
|
class CThreadManualEvent : public CThreadEvent
|
||
|
{
|
||
|
public:
|
||
|
CThreadManualEvent()
|
||
|
: CThreadEvent(true)
|
||
|
{
|
||
|
}
|
||
|
};
|
||
|
|
||
|
inline int ThreadWaitForEvents(int nEvents, CThreadEvent* const* pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE)
|
||
|
{
|
||
|
#ifdef POSIX
|
||
|
Assert(nEvents == 1);
|
||
|
if (pEvents[0]->Wait(timeout))
|
||
|
return WAIT_OBJECT_0;
|
||
|
else
|
||
|
return WAIT_TIMEOUT;
|
||
|
#else
|
||
|
HANDLE handles[64];
|
||
|
for (unsigned int i = 0; i < min(nEvents, ARRAYSIZE(handles)); i++)
|
||
|
handles[i] = pEvents[i]->GetHandle();
|
||
|
return ThreadWaitForObjects(nEvents, handles, bWaitAll, timeout);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
class PLATFORM_CLASS CThreadRWLock
|
||
|
{
|
||
|
public:
|
||
|
CThreadRWLock();
|
||
|
|
||
|
void LockForRead();
|
||
|
void UnlockRead();
|
||
|
void LockForWrite();
|
||
|
void UnlockWrite();
|
||
|
|
||
|
void LockForRead() const { const_cast<CThreadRWLock*>(this)->LockForRead(); }
|
||
|
void UnlockRead() const { const_cast<CThreadRWLock*>(this)->UnlockRead(); }
|
||
|
void LockForWrite() const { const_cast<CThreadRWLock*>(this)->LockForWrite(); }
|
||
|
void UnlockWrite() const { const_cast<CThreadRWLock*>(this)->UnlockWrite(); }
|
||
|
|
||
|
private:
|
||
|
void WaitForRead();
|
||
|
|
||
|
#ifdef WIN32
|
||
|
CThreadFastMutex m_mutex;
|
||
|
#else
|
||
|
CThreadMutex m_mutex;
|
||
|
#endif
|
||
|
CThreadEvent m_CanWrite;
|
||
|
CThreadEvent m_CanRead;
|
||
|
|
||
|
int m_nWriters;
|
||
|
int m_nActiveReaders;
|
||
|
int m_nPendingReaders;
|
||
|
};
|
||
|
|
||
|
class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock
|
||
|
{
|
||
|
public:
|
||
|
CThreadSpinRWLock() { COMPILE_TIME_ASSERT(sizeof(LockInfo_t) == sizeof(int64)); Assert((intp)this % 8 == 0); memset(this, 0, sizeof(*this)); }
|
||
|
|
||
|
bool TryLockForWrite();
|
||
|
bool TryLockForRead();
|
||
|
|
||
|
void LockForRead();
|
||
|
void UnlockRead();
|
||
|
void LockForWrite();
|
||
|
void UnlockWrite();
|
||
|
|
||
|
bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock*>(this)->TryLockForWrite(); }
|
||
|
bool TryLockForRead() const { return const_cast<CThreadSpinRWLock*>(this)->TryLockForRead(); }
|
||
|
void LockForRead() const { const_cast<CThreadSpinRWLock*>(this)->LockForRead(); }
|
||
|
void UnlockRead() const { const_cast<CThreadSpinRWLock*>(this)->UnlockRead(); }
|
||
|
void LockForWrite() const { const_cast<CThreadSpinRWLock*>(this)->LockForWrite(); }
|
||
|
void UnlockWrite() const { const_cast<CThreadSpinRWLock*>(this)->UnlockWrite(); }
|
||
|
|
||
|
private:
|
||
|
struct LockInfo_t
|
||
|
{
|
||
|
uint32 m_writerId;
|
||
|
int m_nReaders;
|
||
|
};
|
||
|
|
||
|
bool AssignIf(const LockInfo_t& newValue, const LockInfo_t& comperand);
|
||
|
bool TryLockForWrite(const uint32 threadId);
|
||
|
void SpinLockForWrite(const uint32 threadId);
|
||
|
|
||
|
volatile LockInfo_t m_lockInfo;
|
||
|
CInterlockedInt m_nWriters;
|
||
|
} ALIGN8_POST;
|
||
|
|
||
|
class PLATFORM_CLASS CThread
|
||
|
{
|
||
|
public:
|
||
|
CThread();
|
||
|
virtual ~CThread();
|
||
|
|
||
|
const char* GetName();
|
||
|
void SetName(const char*);
|
||
|
|
||
|
size_t CalcStackDepth(void* pStackVariable) { return ((byte*)m_pStackBase - (byte*)pStackVariable); }
|
||
|
|
||
|
virtual bool Start(unsigned nBytesStack = 0);
|
||
|
|
||
|
bool IsAlive();
|
||
|
|
||
|
bool Join(unsigned timeout = TT_INFINITE);
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
HANDLE GetThreadHandle();
|
||
|
uint GetThreadId();
|
||
|
#elif defined( LINUX )
|
||
|
uint GetThreadId();
|
||
|
#endif
|
||
|
|
||
|
int GetResult();
|
||
|
|
||
|
void Stop(int exitCode = 0);
|
||
|
|
||
|
int GetPriority() const;
|
||
|
|
||
|
bool SetPriority(int);
|
||
|
|
||
|
void SuspendCooperative();
|
||
|
|
||
|
void ResumeCooperative();
|
||
|
|
||
|
void BWaitForThreadSuspendCooperative();
|
||
|
|
||
|
#ifndef LINUX
|
||
|
unsigned int Suspend();
|
||
|
|
||
|
unsigned int Resume();
|
||
|
#endif
|
||
|
|
||
|
bool Terminate(int exitCode = 0);
|
||
|
|
||
|
static CThread* GetCurrentCThread();
|
||
|
|
||
|
#ifdef Yield
|
||
|
#undef Yield
|
||
|
#endif
|
||
|
static void Yield();
|
||
|
|
||
|
static void Sleep(unsigned duration);
|
||
|
|
||
|
protected:
|
||
|
|
||
|
virtual bool Init();
|
||
|
|
||
|
virtual int Run() = 0;
|
||
|
|
||
|
virtual void OnExit();
|
||
|
|
||
|
void Cleanup();
|
||
|
|
||
|
bool WaitForCreateComplete(CThreadEvent* pEvent);
|
||
|
|
||
|
typedef unsigned(__stdcall* ThreadProc_t)(void*);
|
||
|
virtual ThreadProc_t GetThreadProc();
|
||
|
virtual bool IsThreadRunning();
|
||
|
|
||
|
CThreadMutex m_Lock;
|
||
|
|
||
|
#ifdef WIN32
|
||
|
ThreadHandle_t GetThreadID() const { return (ThreadHandle_t)m_hThread; }
|
||
|
#else
|
||
|
ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; }
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
enum Flags
|
||
|
{
|
||
|
SUPPORT_STOP_PROTOCOL = 1 << 0
|
||
|
};
|
||
|
|
||
|
struct ThreadInit_t
|
||
|
{
|
||
|
CThread* pThread;
|
||
|
CThreadEvent* pInitCompleteEvent;
|
||
|
bool* pfInitSuccess;
|
||
|
};
|
||
|
|
||
|
static unsigned __stdcall ThreadProc(void* pv);
|
||
|
|
||
|
CThread(const CThread&);
|
||
|
CThread& operator=(const CThread&);
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
HANDLE m_hThread;
|
||
|
ThreadId_t m_threadId;
|
||
|
#elif defined(POSIX)
|
||
|
pthread_t m_threadId;
|
||
|
#endif
|
||
|
CInterlockedInt m_nSuspendCount;
|
||
|
CThreadEvent m_SuspendEvent;
|
||
|
CThreadEvent m_SuspendEventSignal;
|
||
|
int m_result;
|
||
|
char m_szName[32];
|
||
|
void* m_pStackBase;
|
||
|
unsigned m_flags;
|
||
|
};
|
||
|
|
||
|
class PLATFORM_CLASS CValidatableThread : public CThread
|
||
|
{
|
||
|
public:
|
||
|
CValidatableThread()
|
||
|
{
|
||
|
m_bSleepForValidate = false;
|
||
|
m_bSleepingForValidate = false;
|
||
|
}
|
||
|
|
||
|
#ifdef DBGFLAG_VALIDATE
|
||
|
virtual void SleepForValidate() { m_bSleepForValidate = true; }
|
||
|
bool BSleepingForValidate() { return m_bSleepingForValidate; }
|
||
|
virtual void WakeFromValidate() { m_bSleepForValidate = false; }
|
||
|
#endif
|
||
|
protected:
|
||
|
bool m_bSleepForValidate;
|
||
|
bool m_bSleepingForValidate;
|
||
|
};
|
||
|
|
||
|
|
||
|
enum WTCallResult_t
|
||
|
{
|
||
|
WTCR_FAIL = -1,
|
||
|
WTCR_TIMEOUT = -2,
|
||
|
WTCR_THREAD_GONE = -3,
|
||
|
};
|
||
|
|
||
|
class CFunctor;
|
||
|
class PLATFORM_CLASS CWorkerThread : public CThread
|
||
|
{
|
||
|
public:
|
||
|
CWorkerThread();
|
||
|
|
||
|
int CallWorker(unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true, CFunctor* pParamFunctor = NULL);
|
||
|
|
||
|
int CallMaster(unsigned, unsigned timeout = TT_INFINITE);
|
||
|
|
||
|
bool WaitForCall(unsigned dwTimeout, unsigned* pResult = NULL);
|
||
|
bool WaitForCall(unsigned* pResult = NULL);
|
||
|
|
||
|
bool PeekCall(unsigned* pParam = NULL, CFunctor** ppParamFunctor = NULL);
|
||
|
|
||
|
void Reply(unsigned);
|
||
|
|
||
|
int WaitForReply(unsigned timeout = TT_INFINITE);
|
||
|
|
||
|
CThreadEvent& GetCallHandle();
|
||
|
unsigned GetCallParam(CFunctor** ppParamFunctor = NULL) const;
|
||
|
|
||
|
int BoostPriority();
|
||
|
|
||
|
protected:
|
||
|
#ifndef _WIN32
|
||
|
#define __stdcall
|
||
|
#endif
|
||
|
typedef uint32(__stdcall* WaitFunc_t)(int nEvents, CThreadEvent* const* pEvents, int bWaitAll, uint32 timeout);
|
||
|
|
||
|
int Call(unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL, CFunctor* pParamFunctor = NULL);
|
||
|
int WaitForReply(unsigned timeout, WaitFunc_t);
|
||
|
|
||
|
private:
|
||
|
CWorkerThread(const CWorkerThread&);
|
||
|
CWorkerThread& operator=(const CWorkerThread&);
|
||
|
|
||
|
CThreadEvent m_EventSend;
|
||
|
CThreadEvent m_EventComplete;
|
||
|
|
||
|
unsigned m_Param;
|
||
|
CFunctor* m_pParamFunctor;
|
||
|
int m_ReturnVal;
|
||
|
};
|
||
|
|
||
|
|
||
|
template<class T> class CMessageQueue
|
||
|
{
|
||
|
CThreadEvent SignalEvent;
|
||
|
CThreadMutex QueueAccessMutex;
|
||
|
|
||
|
struct MsgNode
|
||
|
{
|
||
|
MsgNode* Next;
|
||
|
T Data;
|
||
|
};
|
||
|
|
||
|
MsgNode* Head;
|
||
|
MsgNode* Tail;
|
||
|
|
||
|
public:
|
||
|
CMessageQueue(void)
|
||
|
{
|
||
|
Head = Tail = NULL;
|
||
|
}
|
||
|
|
||
|
bool MessageWaiting(void)
|
||
|
{
|
||
|
return (Head != NULL);
|
||
|
}
|
||
|
|
||
|
void WaitMessage(T* pMsg)
|
||
|
{
|
||
|
for (;;)
|
||
|
{
|
||
|
while (!MessageWaiting())
|
||
|
SignalEvent.Wait();
|
||
|
QueueAccessMutex.Lock();
|
||
|
if (!Head)
|
||
|
{
|
||
|
QueueAccessMutex.Unlock();
|
||
|
continue;
|
||
|
}
|
||
|
*(pMsg) = Head->Data;
|
||
|
MsgNode* remove_this = Head;
|
||
|
Head = Head->Next;
|
||
|
if (!Head)
|
||
|
Tail = NULL;
|
||
|
QueueAccessMutex.Unlock();
|
||
|
delete remove_this;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QueueMessage(T const& Msg)
|
||
|
{
|
||
|
MsgNode* new1 = new MsgNode;
|
||
|
new1->Data = Msg;
|
||
|
new1->Next = NULL;
|
||
|
QueueAccessMutex.Lock();
|
||
|
if (Tail)
|
||
|
{
|
||
|
Tail->Next = new1;
|
||
|
Tail = new1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Head = new1;
|
||
|
Tail = new1;
|
||
|
}
|
||
|
SignalEvent.Set();
|
||
|
QueueAccessMutex.Unlock();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION;
|
||
|
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
|
||
|
|
||
|
#ifndef _X360
|
||
|
extern "C"
|
||
|
{
|
||
|
void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION*);
|
||
|
void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION*);
|
||
|
void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION*);
|
||
|
void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION*);
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
inline void CThreadMutex::Lock()
|
||
|
{
|
||
|
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||
|
uint thisThreadID = ThreadGetCurrentId();
|
||
|
if (m_bTrace && m_currentOwnerID && (m_currentOwnerID != thisThreadID))
|
||
|
Msg("Thread %u about to wait for lock %p owned by %u\n", ThreadGetCurrentId(), (CRITICAL_SECTION*)&m_CriticalSection, m_currentOwnerID);
|
||
|
#endif
|
||
|
|
||
|
VCRHook_EnterCriticalSection((CRITICAL_SECTION*)&m_CriticalSection);
|
||
|
|
||
|
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||
|
if (m_lockCount == 0)
|
||
|
{
|
||
|
m_currentOwnerID = thisThreadID;
|
||
|
if (m_bTrace)
|
||
|
Msg("Thread %u now owns lock %p\n", m_currentOwnerID, (CRITICAL_SECTION*)&m_CriticalSection);
|
||
|
}
|
||
|
m_lockCount++;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline void CThreadMutex::Unlock()
|
||
|
{
|
||
|
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||
|
AssertMsg(m_lockCount >= 1, "Invalid unlock of thread lock");
|
||
|
m_lockCount--;
|
||
|
if (m_lockCount == 0)
|
||
|
{
|
||
|
if (m_bTrace)
|
||
|
Msg("Thread %u releasing lock %p\n", m_currentOwnerID, (CRITICAL_SECTION*)&m_CriticalSection);
|
||
|
m_currentOwnerID = 0;
|
||
|
}
|
||
|
#endif
|
||
|
LeaveCriticalSection((CRITICAL_SECTION*)&m_CriticalSection);
|
||
|
}
|
||
|
|
||
|
inline bool CThreadMutex::AssertOwnedByCurrentThread()
|
||
|
{
|
||
|
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||
|
if (ThreadGetCurrentId() == m_currentOwnerID)
|
||
|
return true;
|
||
|
AssertMsg3(0, "Expected thread %u as owner of lock %p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION*)&m_CriticalSection, m_currentOwnerID);
|
||
|
return false;
|
||
|
#else
|
||
|
return true;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
inline void CThreadMutex::SetTrace(bool bTrace)
|
||
|
{
|
||
|
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||
|
m_bTrace = bTrace;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#elif defined(POSIX)
|
||
|
|
||
|
inline CThreadMutex::CThreadMutex()
|
||
|
{
|
||
|
pthread_mutexattr_init(&m_Attr);
|
||
|
pthread_mutexattr_settype(&m_Attr, PTHREAD_MUTEX_RECURSIVE);
|
||
|
pthread_mutex_init(&m_Mutex, &m_Attr);
|
||
|
}
|
||
|
|
||
|
inline CThreadMutex::~CThreadMutex()
|
||
|
{
|
||
|
pthread_mutex_destroy(&m_Mutex);
|
||
|
}
|
||
|
|
||
|
inline void CThreadMutex::Lock()
|
||
|
{
|
||
|
pthread_mutex_lock(&m_Mutex);
|
||
|
}
|
||
|
|
||
|
inline void CThreadMutex::Unlock()
|
||
|
{
|
||
|
pthread_mutex_unlock(&m_Mutex);
|
||
|
}
|
||
|
|
||
|
inline bool CThreadMutex::AssertOwnedByCurrentThread()
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline void CThreadMutex::SetTrace(bool fTrace)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
inline CThreadRWLock::CThreadRWLock()
|
||
|
: m_CanRead(true),
|
||
|
m_nWriters(0),
|
||
|
m_nActiveReaders(0),
|
||
|
m_nPendingReaders(0)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline void CThreadRWLock::LockForRead()
|
||
|
{
|
||
|
m_mutex.Lock();
|
||
|
if (m_nWriters)
|
||
|
{
|
||
|
WaitForRead();
|
||
|
}
|
||
|
m_nActiveReaders++;
|
||
|
m_mutex.Unlock();
|
||
|
}
|
||
|
|
||
|
inline void CThreadRWLock::UnlockRead()
|
||
|
{
|
||
|
m_mutex.Lock();
|
||
|
m_nActiveReaders--;
|
||
|
if (m_nActiveReaders == 0 && m_nWriters != 0)
|
||
|
{
|
||
|
m_CanWrite.Set();
|
||
|
}
|
||
|
m_mutex.Unlock();
|
||
|
}
|
||
|
|
||
|
|
||
|
inline bool CThreadSpinRWLock::AssignIf(const LockInfo_t& newValue, const LockInfo_t& comperand)
|
||
|
{
|
||
|
return ThreadInterlockedAssignIf64((int64*)&m_lockInfo, *((int64*)&newValue), *((int64*)&comperand));
|
||
|
}
|
||
|
|
||
|
inline bool CThreadSpinRWLock::TryLockForWrite(const uint32 threadId)
|
||
|
{
|
||
|
if (m_lockInfo.m_nReaders > 0 || (m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static const LockInfo_t oldValue = { 0, 0 };
|
||
|
LockInfo_t newValue = { threadId, 0 };
|
||
|
const bool bSuccess = AssignIf(newValue, oldValue);
|
||
|
#if defined(_X360)
|
||
|
if (bSuccess)
|
||
|
{
|
||
|
}
|
||
|
#endif
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
inline bool CThreadSpinRWLock::TryLockForWrite()
|
||
|
{
|
||
|
m_nWriters++;
|
||
|
if (!TryLockForWrite(ThreadGetCurrentId()))
|
||
|
{
|
||
|
m_nWriters--;
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
inline bool CThreadSpinRWLock::TryLockForRead()
|
||
|
{
|
||
|
if (m_nWriters != 0)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
LockInfo_t oldValue;
|
||
|
LockInfo_t newValue;
|
||
|
|
||
|
oldValue.m_nReaders = m_lockInfo.m_nReaders;
|
||
|
oldValue.m_writerId = 0;
|
||
|
newValue.m_nReaders = oldValue.m_nReaders + 1;
|
||
|
newValue.m_writerId = 0;
|
||
|
|
||
|
const bool bSuccess = AssignIf(newValue, oldValue);
|
||
|
#if defined(_X360)
|
||
|
if (bSuccess)
|
||
|
{
|
||
|
}
|
||
|
#endif
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
inline void CThreadSpinRWLock::LockForWrite()
|
||
|
{
|
||
|
const uint32 threadId = ThreadGetCurrentId();
|
||
|
|
||
|
m_nWriters++;
|
||
|
|
||
|
if (!TryLockForWrite(threadId))
|
||
|
{
|
||
|
ThreadPause();
|
||
|
SpinLockForWrite(threadId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<class T> FORCEINLINE T ReadVolatileMemory(T const* pPtr)
|
||
|
{
|
||
|
volatile const T* pVolatilePtr = (volatile const T*)pPtr;
|
||
|
return *pVolatilePtr;
|
||
|
}
|
||
|
|
||
|
#if defined( _WIN32 )
|
||
|
#pragma warning(pop)
|
||
|
#endif
|
||
|
|
||
|
#endif
|