Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1825 lines
57 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A collection of utility classes to simplify thread handling, and
  4. // as much as possible contain portability problems. Here avoiding
  5. // including windows.h.
  6. //
  7. //=============================================================================
  8. #ifndef THREADTOOLS_H
  9. #define THREADTOOLS_H
  10. #include "tier0/type_traits.h"
  11. #include <limits.h>
  12. #include "tier0/platform.h"
  13. #include "tier0/dbg.h"
  14. #include "tier0/vcrmode.h"
  15. #include "tier0/vprof_telemetry.h"
  16. #ifdef PLATFORM_WINDOWS_PC
  17. #include <intrin.h>
  18. #endif
  19. #ifdef POSIX
  20. #include <pthread.h>
  21. #include <errno.h>
  22. #define WAIT_OBJECT_0 0
  23. #define WAIT_TIMEOUT 0x00000102
  24. #define WAIT_FAILED -1
  25. #define THREAD_PRIORITY_HIGHEST 2
  26. #endif
  27. #if defined( _WIN32 )
  28. #pragma once
  29. #pragma warning(push)
  30. #pragma warning(disable:4251)
  31. #endif
  32. // #define THREAD_PROFILER 1
  33. #ifndef _RETAIL
  34. #define THREAD_MUTEX_TRACING_SUPPORTED
  35. #if defined(_WIN32) && defined(_DEBUG)
  36. #define THREAD_MUTEX_TRACING_ENABLED
  37. #endif
  38. #endif
  39. #ifdef _WIN32
  40. typedef void *HANDLE;
  41. #endif
  42. // Start thread running - error if already running
  43. enum ThreadPriorityEnum_t
  44. {
  45. #if defined( PLATFORM_PS3 )
  46. TP_PRIORITY_NORMAL = 1001,
  47. TP_PRIORITY_HIGH = 100,
  48. TP_PRIORITY_LOW = 2001,
  49. TP_PRIORITY_DEFAULT = 1001
  50. #error "Need PRIORITY_LOWEST/HIGHEST"
  51. #elif defined( PLATFORM_LINUX )
  52. // We can use nice on Linux threads to change scheduling.
  53. // pthreads on Linux only allows priority setting on
  54. // real-time threads.
  55. // NOTE: Lower numbers are higher priority, thus the need
  56. // for TP_IS_PRIORITY_HIGHER.
  57. TP_PRIORITY_DEFAULT = 0,
  58. TP_PRIORITY_NORMAL = 0,
  59. TP_PRIORITY_HIGH = -10,
  60. TP_PRIORITY_LOW = 10,
  61. TP_PRIORITY_HIGHEST = -20,
  62. TP_PRIORITY_LOWEST = 19,
  63. #else // PLATFORM_PS3
  64. TP_PRIORITY_DEFAULT = 0, // THREAD_PRIORITY_NORMAL
  65. TP_PRIORITY_NORMAL = 0, // THREAD_PRIORITY_NORMAL
  66. TP_PRIORITY_HIGH = 1, // THREAD_PRIORITY_ABOVE_NORMAL
  67. TP_PRIORITY_LOW = -1, // THREAD_PRIORITY_BELOW_NORMAL
  68. TP_PRIORITY_HIGHEST = 2, // THREAD_PRIORITY_HIGHEST
  69. TP_PRIORITY_LOWEST = -2, // THREAD_PRIORITY_LOWEST
  70. #endif // PLATFORM_PS3
  71. };
  72. //-----------------------------------------------------------------------------
  73. //
  74. //-----------------------------------------------------------------------------
  75. const unsigned TT_INFINITE = 0xffffffff;
  76. #ifndef NO_THREAD_LOCAL
  77. #ifndef THREAD_LOCAL
  78. #ifdef _WIN32
  79. #define THREAD_LOCAL __declspec(thread)
  80. #elif POSIX
  81. #define THREAD_LOCAL __thread
  82. #endif
  83. #endif
  84. #endif // NO_THREAD_LOCAL
  85. typedef unsigned long ThreadId_t;
  86. //-----------------------------------------------------------------------------
  87. //
  88. // Simple thread creation. Differs from VCR mode/CreateThread/_beginthreadex
  89. // in that it accepts a standard C function rather than compiler specific one.
  90. //
  91. //-----------------------------------------------------------------------------
  92. FORWARD_DECLARE_HANDLE( ThreadHandle_t );
  93. typedef unsigned (*ThreadFunc_t)( void *pParam );
  94. PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 );
  95. PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 );
  96. PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t );
  97. //-----------------------------------------------------------------------------
  98. PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0);
  99. PLATFORM_INTERFACE uint ThreadGetCurrentId();
  100. PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle();
  101. PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL );
  102. PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority );
  103. inline bool ThreadSetPriority( int priority ) { return ThreadSetPriority( NULL, priority ); }
  104. PLATFORM_INTERFACE bool ThreadInMainThread();
  105. PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread();
  106. // NOTE: ThreadedLoadLibraryFunc_t needs to return the sleep time in milliseconds or TT_INFINITE
  107. typedef int (*ThreadedLoadLibraryFunc_t)();
  108. PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func );
  109. PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc();
  110. #if defined( _WIN32 ) && !defined( _WIN64 ) && !defined( _X360 )
  111. extern "C" unsigned long __declspec(dllimport) __stdcall GetCurrentThreadId();
  112. #define ThreadGetCurrentId GetCurrentThreadId
  113. #endif
  114. inline void ThreadPause()
  115. {
  116. #if defined( PLATFORM_WINDOWS_PC )
  117. // Intrinsic for __asm pause; from <intrin.h>
  118. _mm_pause();
  119. #elif POSIX
  120. __asm __volatile( "pause" );
  121. #elif defined( _X360 )
  122. #else
  123. #error "implement me"
  124. #endif
  125. }
  126. PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE );
  127. // If you're not calling ThreadJoin, you need to call ThreadDetach so pthreads on Linux knows it can
  128. // free the memory for this thread. Otherwise you wind up leaking threads until you run out and
  129. // CreateSimpleThread() will fail.
  130. PLATFORM_INTERFACE void ThreadDetach( ThreadHandle_t );
  131. PLATFORM_INTERFACE void ThreadSetDebugName( ThreadId_t id, const char *pszName );
  132. inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( (ThreadId_t)-1, pszName ); }
  133. PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask );
  134. //-----------------------------------------------------------------------------
  135. enum ThreadWaitResult_t
  136. {
  137. TW_FAILED = 0xffffffff, // WAIT_FAILED
  138. TW_TIMEOUT = 0x00000102, // WAIT_TIMEOUT
  139. };
  140. #ifdef _WIN32
  141. PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE );
  142. inline int ThreadWaitForObject( HANDLE handle, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( 1, &handle, bWaitAll, timeout ); }
  143. #endif
  144. //-----------------------------------------------------------------------------
  145. //
  146. // Interlock methods. These perform very fast atomic thread
  147. // safe operations. These are especially relevant in a multi-core setting.
  148. //
  149. //-----------------------------------------------------------------------------
  150. #ifdef _WIN32
  151. #define NOINLINE
  152. #elif POSIX
  153. #define NOINLINE __attribute__ ((noinline))
  154. #endif
  155. // ThreadMemoryBarrier is a fence/barrier sufficient for most uses. It prevents reads
  156. // from moving past reads, and writes moving past writes. It is sufficient for
  157. // read-acquire and write-release barriers. It is not a full barrier and it does
  158. // not prevent reads from moving past writes -- that would require a full __sync()
  159. // on PPC and is significantly more expensive.
  160. #if defined( _X360 ) || defined( _PS3 )
  161. #define ThreadMemoryBarrier() __lwsync()
  162. #elif defined(_MSC_VER)
  163. // Prevent compiler reordering across this barrier. This is
  164. // sufficient for most purposes on x86/x64.
  165. #if _MSC_VER < 1500
  166. // !KLUDGE! For VC 2005
  167. // http://connect.microsoft.com/VisualStudio/feedback/details/100051
  168. #pragma intrinsic(_ReadWriteBarrier)
  169. #endif
  170. #define ThreadMemoryBarrier() _ReadWriteBarrier()
  171. #elif defined(GNUC)
  172. // Prevent compiler reordering across this barrier. This is
  173. // sufficient for most purposes on x86/x64.
  174. // http://preshing.com/20120625/memory-ordering-at-compile-time
  175. #define ThreadMemoryBarrier() asm volatile("" ::: "memory")
  176. #else
  177. #error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering
  178. #endif
  179. #if defined(_WIN32) && !defined(_X360)
  180. #if ( _MSC_VER >= 1310 )
  181. #define USE_INTRINSIC_INTERLOCKED
  182. #endif
  183. #endif
  184. #ifdef USE_INTRINSIC_INTERLOCKED
  185. extern "C"
  186. {
  187. long __cdecl _InterlockedIncrement(volatile long*);
  188. long __cdecl _InterlockedDecrement(volatile long*);
  189. long __cdecl _InterlockedExchange(volatile long*, long);
  190. long __cdecl _InterlockedExchangeAdd(volatile long*, long);
  191. long __cdecl _InterlockedCompareExchange(volatile long*, long, long);
  192. }
  193. #pragma intrinsic( _InterlockedCompareExchange )
  194. #pragma intrinsic( _InterlockedDecrement )
  195. #pragma intrinsic( _InterlockedExchange )
  196. #pragma intrinsic( _InterlockedExchangeAdd )
  197. #pragma intrinsic( _InterlockedIncrement )
  198. inline long ThreadInterlockedIncrement( long volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( p ); }
  199. inline long ThreadInterlockedDecrement( long volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( p ); }
  200. inline long ThreadInterlockedExchange( long volatile *p, long value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( p, value ); }
  201. inline long ThreadInterlockedExchangeAdd( long volatile *p, long value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( p, value ); }
  202. inline long ThreadInterlockedCompareExchange( long volatile *p, long value, long comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( p, value, comperand ); }
  203. inline bool ThreadInterlockedAssignIf( long volatile *p, long value, long comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( p, value, comperand ) == comperand ); }
  204. #else
  205. PLATFORM_INTERFACE long ThreadInterlockedIncrement( long volatile * );
  206. PLATFORM_INTERFACE long ThreadInterlockedDecrement( long volatile * );
  207. PLATFORM_INTERFACE long ThreadInterlockedExchange( long volatile *, long value );
  208. PLATFORM_INTERFACE long ThreadInterlockedExchangeAdd( long volatile *, long value );
  209. PLATFORM_INTERFACE long ThreadInterlockedCompareExchange( long volatile *, long value, long comperand );
  210. PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( long volatile *, long value, long comperand );
  211. #endif
  212. inline unsigned ThreadInterlockedExchangeSubtract( long volatile *p, long value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, -value ); }
  213. #if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( _WIN64 )
  214. #define TIPTR()
  215. inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)_InterlockedExchange( reinterpret_cast<long volatile *>(p), reinterpret_cast<long>(value) ); }
  216. 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) ); }
  217. 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) ); }
  218. #else
  219. PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE;
  220. PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE;
  221. PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE;
  222. #endif
  223. inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); }
  224. 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 ) ); }
  225. 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 ) ); }
  226. #if defined( PLATFORM_64BITS )
  227. #if defined (_WIN32)
  228. typedef __m128i int128;
  229. inline int128 int128_zero() { return _mm_setzero_si128(); }
  230. #else
  231. typedef __int128_t int128;
  232. #define int128_zero() 0
  233. #endif
  234. PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) NOINLINE;
  235. #endif
  236. PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE;
  237. PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE;
  238. PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE;
  239. PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE;
  240. PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE;
  241. PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE;
  242. inline unsigned ThreadInterlockedExchangeSubtract( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); }
  243. inline unsigned ThreadInterlockedIncrement( unsigned volatile *p ) { return ThreadInterlockedIncrement( (long volatile *)p ); }
  244. inline unsigned ThreadInterlockedDecrement( unsigned volatile *p ) { return ThreadInterlockedDecrement( (long volatile *)p ); }
  245. inline unsigned ThreadInterlockedExchange( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchange( (long volatile *)p, value ); }
  246. inline unsigned ThreadInterlockedExchangeAdd( unsigned volatile *p, unsigned value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); }
  247. inline unsigned ThreadInterlockedCompareExchange( unsigned volatile *p, unsigned value, unsigned comperand ) { return ThreadInterlockedCompareExchange( (long volatile *)p, value, comperand ); }
  248. inline bool ThreadInterlockedAssignIf( unsigned volatile *p, unsigned value, unsigned comperand ) { return ThreadInterlockedAssignIf( (long volatile *)p, value, comperand ); }
  249. inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); }
  250. inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (long volatile *)p ); }
  251. inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (long volatile *)p ); }
  252. inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (long volatile *)p, value ); }
  253. inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (long volatile *)p, value ); }
  254. inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (long volatile *)p, value, comperand ); }
  255. inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (long volatile *)p, value, comperand ); }
  256. //-----------------------------------------------------------------------------
  257. // Access to VTune thread profiling
  258. //-----------------------------------------------------------------------------
  259. #if defined(_WIN32) && defined(THREAD_PROFILER)
  260. PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void *p);
  261. PLATFORM_INTERFACE void ThreadNotifySyncCancel(void *p);
  262. PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void *p);
  263. PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p);
  264. #else
  265. #define ThreadNotifySyncPrepare(p) ((void)0)
  266. #define ThreadNotifySyncCancel(p) ((void)0)
  267. #define ThreadNotifySyncAcquired(p) ((void)0)
  268. #define ThreadNotifySyncReleasing(p) ((void)0)
  269. #endif
  270. //-----------------------------------------------------------------------------
  271. // Encapsulation of a thread local datum (needed because THREAD_LOCAL doesn't
  272. // work in a DLL loaded with LoadLibrary()
  273. //-----------------------------------------------------------------------------
  274. #ifndef NO_THREAD_LOCAL
  275. #if defined(_LINUX) && !defined(OSX)
  276. // linux totally supports compiler thread locals, even across dll's.
  277. #define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1
  278. #define CTHREADLOCALINTEGER( typ ) __thread int
  279. #define CTHREADLOCALINT __thread int
  280. #define CTHREADLOCALPTR( typ ) __thread typ *
  281. #define CTHREADLOCAL( typ ) __thread typ
  282. #define GETLOCAL( x ) ( x )
  283. #endif // _LINUX && !OSX
  284. #if defined(WIN32) || defined(OSX)
  285. #ifndef __AFXTLS_H__ // not compatible with some Windows headers
  286. #define CTHREADLOCALINT CThreadLocalInt<int>
  287. #define CTHREADLOCALINTEGER( typ ) CThreadLocalInt<typ>
  288. #define CTHREADLOCALPTR( typ ) CThreadLocalPtr<typ>
  289. #define CTHREADLOCAL( typ ) CThreadLocal<typ>
  290. #define GETLOCAL( x ) ( x.Get() )
  291. #endif
  292. #endif // WIN32 || OSX
  293. #endif // NO_THREAD_LOCALS
  294. #ifndef __AFXTLS_H__ // not compatible with some Windows headers
  295. #ifndef NO_THREAD_LOCAL
  296. class PLATFORM_CLASS CThreadLocalBase
  297. {
  298. public:
  299. CThreadLocalBase();
  300. ~CThreadLocalBase();
  301. void * Get() const;
  302. void Set(void *);
  303. private:
  304. #ifdef _WIN32
  305. uint32 m_index;
  306. #elif POSIX
  307. pthread_key_t m_index;
  308. #endif
  309. };
  310. //---------------------------------------------------------
  311. #ifndef __AFXTLS_H__
  312. template <class T>
  313. class CThreadLocal : public CThreadLocalBase
  314. {
  315. public:
  316. CThreadLocal()
  317. {
  318. COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) );
  319. }
  320. T Get() const
  321. {
  322. return reinterpret_cast<T>( CThreadLocalBase::Get() );
  323. }
  324. void Set(T val)
  325. {
  326. CThreadLocalBase::Set( reinterpret_cast<void *>(val) );
  327. }
  328. };
  329. #endif
  330. //---------------------------------------------------------
  331. template <class T = intp>
  332. class CThreadLocalInt : public CThreadLocal<T>
  333. {
  334. public:
  335. CThreadLocalInt()
  336. {
  337. COMPILE_TIME_ASSERT( sizeof(T) >= sizeof(int) );
  338. }
  339. operator int() const { return (int)this->Get(); }
  340. int operator=( int i ) { this->Set( (intp)i ); return i; }
  341. int operator++() { T i = this->Get(); this->Set( ++i ); return (int)i; }
  342. int operator++(int) { T i = this->Get(); this->Set( i + 1 ); return (int)i; }
  343. int operator--() { T i = this->Get(); this->Set( --i ); return (int)i; }
  344. int operator--(int) { T i = this->Get(); this->Set( i - 1 ); return (int)i; }
  345. };
  346. //---------------------------------------------------------
  347. template <class T>
  348. class CThreadLocalPtr : private CThreadLocalBase
  349. {
  350. public:
  351. CThreadLocalPtr() {}
  352. operator const void *() const { return (T *)Get(); }
  353. operator void *() { return (T *)Get(); }
  354. operator const T *() const { return (T *)Get(); }
  355. operator const T *() { return (T *)Get(); }
  356. operator T *() { return (T *)Get(); }
  357. int operator=( int i ) { AssertMsg( i == 0, "Only NULL allowed on integer assign" ); Set( NULL ); return 0; }
  358. T * operator=( T *p ) { Set( p ); return p; }
  359. bool operator !() const { return (!Get()); }
  360. bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); }
  361. bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); }
  362. bool operator==( const void *p ) const { return (Get() == p); }
  363. bool operator!=( const void *p ) const { return (Get() != p); }
  364. bool operator==( const T *p ) const { return operator==((void*)p); }
  365. bool operator!=( const T *p ) const { return operator!=((void*)p); }
  366. T * operator->() { return (T *)Get(); }
  367. T & operator *() { return *((T *)Get()); }
  368. const T * operator->() const { return (T *)Get(); }
  369. const T & operator *() const { return *((T *)Get()); }
  370. const T & operator[]( int i ) const { return *((T *)Get() + i); }
  371. T & operator[]( int i ) { return *((T *)Get() + i); }
  372. private:
  373. // Disallowed operations
  374. CThreadLocalPtr( T *pFrom );
  375. CThreadLocalPtr( const CThreadLocalPtr<T> &from );
  376. T **operator &();
  377. T * const *operator &() const;
  378. void operator=( const CThreadLocalPtr<T> &from );
  379. bool operator==( const CThreadLocalPtr<T> &p ) const;
  380. bool operator!=( const CThreadLocalPtr<T> &p ) const;
  381. };
  382. #endif // NO_THREAD_LOCAL
  383. #endif // !__AFXTLS_H__
  384. //-----------------------------------------------------------------------------
  385. //
  386. // A super-fast thread-safe integer A simple class encapsulating the notion of an
  387. // atomic integer used across threads that uses the built in and faster
  388. // "interlocked" functionality rather than a full-blown mutex. Useful for simple
  389. // things like reference counts, etc.
  390. //
  391. //-----------------------------------------------------------------------------
  392. template <typename T>
  393. class CInterlockedIntT
  394. {
  395. public:
  396. CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T) == sizeof(long) ); }
  397. CInterlockedIntT( T value ) : m_value( value ) {}
  398. T GetRaw() const { return m_value; }
  399. operator T() const { return m_value; }
  400. bool operator!() const { return ( m_value == 0 ); }
  401. bool operator==( T rhs ) const { return ( m_value == rhs ); }
  402. bool operator!=( T rhs ) const { return ( m_value != rhs ); }
  403. T operator++() { return (T)ThreadInterlockedIncrement( (long *)&m_value ); }
  404. T operator++(int) { return operator++() - 1; }
  405. T operator--() { return (T)ThreadInterlockedDecrement( (long *)&m_value ); }
  406. T operator--(int) { return operator--() + 1; }
  407. bool AssignIf( T conditionValue, T newValue ) { return ThreadInterlockedAssignIf( (long *)&m_value, (long)newValue, (long)conditionValue ); }
  408. T operator=( T newValue ) { ThreadInterlockedExchange((long *)&m_value, newValue); return m_value; }
  409. void operator+=( T add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, (long)add ); }
  410. void operator-=( T subtract ) { operator+=( -subtract ); }
  411. void operator*=( T multiplier ) {
  412. T original, result;
  413. do
  414. {
  415. original = m_value;
  416. result = original * multiplier;
  417. } while ( !AssignIf( original, result ) );
  418. }
  419. void operator/=( T divisor ) {
  420. T original, result;
  421. do
  422. {
  423. original = m_value;
  424. result = original / divisor;
  425. } while ( !AssignIf( original, result ) );
  426. }
  427. T operator+( T rhs ) const { return m_value + rhs; }
  428. T operator-( T rhs ) const { return m_value - rhs; }
  429. private:
  430. volatile T m_value;
  431. };
  432. typedef CInterlockedIntT<int> CInterlockedInt;
  433. typedef CInterlockedIntT<unsigned> CInterlockedUInt;
  434. //-----------------------------------------------------------------------------
  435. template <typename T>
  436. class CInterlockedPtr
  437. {
  438. public:
  439. CInterlockedPtr() : m_value( 0 ) {}
  440. CInterlockedPtr( T *value ) : m_value( value ) {}
  441. operator T *() const { return m_value; }
  442. bool operator!() const { return ( m_value == 0 ); }
  443. bool operator==( T *rhs ) const { return ( m_value == rhs ); }
  444. bool operator!=( T *rhs ) const { return ( m_value != rhs ); }
  445. #if defined( PLATFORM_64BITS )
  446. T *operator++() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) )) + 1; }
  447. T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, sizeof(T) ); }
  448. T *operator--() { return ((T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, -sizeof(T) )) - 1; }
  449. T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, -sizeof(T) ); }
  450. bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); }
  451. T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; }
  452. void operator+=( int add ) { ThreadInterlockedExchangeAdd64( (int64 *)&m_value, add * sizeof(T) ); }
  453. #else
  454. T *operator++() { return ((T *)ThreadInterlockedExchangeAdd( (long *)&m_value, sizeof(T) )) + 1; }
  455. T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (long *)&m_value, sizeof(T) ); }
  456. T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (long *)&m_value, -sizeof(T) )) - 1; }
  457. T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (long *)&m_value, -sizeof(T) ); }
  458. bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); }
  459. T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; }
  460. void operator+=( int add ) { ThreadInterlockedExchangeAdd( (long *)&m_value, add * sizeof(T) ); }
  461. #endif
  462. void operator-=( int subtract ) { operator+=( -subtract ); }
  463. T *operator+( int rhs ) const { return m_value + rhs; }
  464. T *operator-( int rhs ) const { return m_value - rhs; }
  465. T *operator+( unsigned rhs ) const { return m_value + rhs; }
  466. T *operator-( unsigned rhs ) const { return m_value - rhs; }
  467. size_t operator-( T *p ) const { return m_value - p; }
  468. size_t operator-( const CInterlockedPtr<T> &p ) const { return m_value - p.m_value; }
  469. private:
  470. T * volatile m_value;
  471. };
  472. //-----------------------------------------------------------------------------
  473. //
  474. // Platform independent verification that multiple threads aren't getting into the same code at the same time.
  475. // Note: This is intended for use to identify problems, it doesn't provide any sort of thread safety.
  476. //
  477. //-----------------------------------------------------------------------------
  478. class ReentrancyVerifier
  479. {
  480. public:
  481. inline ReentrancyVerifier(CInterlockedInt* counter, int sleepTimeMS)
  482. : mCounter(counter)
  483. {
  484. Assert(mCounter != NULL);
  485. if (++(*mCounter) != 1) {
  486. DebuggerBreakIfDebugging_StagingOnly();
  487. }
  488. if (sleepTimeMS > 0)
  489. {
  490. ThreadSleep(sleepTimeMS);
  491. }
  492. }
  493. inline ~ReentrancyVerifier()
  494. {
  495. if (--(*mCounter) != 0) {
  496. DebuggerBreakIfDebugging_StagingOnly();
  497. }
  498. }
  499. private:
  500. CInterlockedInt* mCounter;
  501. };
  502. //-----------------------------------------------------------------------------
  503. //
  504. // Platform independent for critical sections management
  505. //
  506. //-----------------------------------------------------------------------------
  507. class PLATFORM_CLASS CThreadMutex
  508. {
  509. public:
  510. CThreadMutex();
  511. ~CThreadMutex();
  512. //------------------------------------------------------
  513. // Mutex acquisition/release. Const intentionally defeated.
  514. //------------------------------------------------------
  515. void Lock();
  516. void Lock() const { (const_cast<CThreadMutex *>(this))->Lock(); }
  517. void Unlock();
  518. void Unlock() const { (const_cast<CThreadMutex *>(this))->Unlock(); }
  519. bool TryLock();
  520. bool TryLock() const { return (const_cast<CThreadMutex *>(this))->TryLock(); }
  521. //------------------------------------------------------
  522. // Use this to make deadlocks easier to track by asserting
  523. // when it is expected that the current thread owns the mutex
  524. //------------------------------------------------------
  525. bool AssertOwnedByCurrentThread();
  526. //------------------------------------------------------
  527. // Enable tracing to track deadlock problems
  528. //------------------------------------------------------
  529. void SetTrace( bool );
  530. private:
  531. // Disallow copying
  532. CThreadMutex( const CThreadMutex & );
  533. CThreadMutex &operator=( const CThreadMutex & );
  534. #if defined( _WIN32 )
  535. // Efficient solution to breaking the windows.h dependency, invariant is tested.
  536. #ifdef _WIN64
  537. #define TT_SIZEOF_CRITICALSECTION 40
  538. #else
  539. #ifndef _X360
  540. #define TT_SIZEOF_CRITICALSECTION 24
  541. #else
  542. #define TT_SIZEOF_CRITICALSECTION 28
  543. #endif // !_XBOX
  544. #endif // _WIN64
  545. byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION];
  546. #elif defined(POSIX)
  547. pthread_mutex_t m_Mutex;
  548. pthread_mutexattr_t m_Attr;
  549. #else
  550. #error
  551. #endif
  552. #ifdef THREAD_MUTEX_TRACING_SUPPORTED
  553. // Debugging (always here to allow mixed debug/release builds w/o changing size)
  554. uint m_currentOwnerID;
  555. uint16 m_lockCount;
  556. bool m_bTrace;
  557. #endif
  558. };
  559. //-----------------------------------------------------------------------------
  560. //
  561. // An alternative mutex that is useful for cases when thread contention is
  562. // rare, but a mutex is required. Instances should be declared volatile.
  563. // Sleep of 0 may not be sufficient to keep high priority threads from starving
  564. // lesser threads. This class is not a suitable replacement for a critical
  565. // section if the resource contention is high.
  566. //
  567. //-----------------------------------------------------------------------------
  568. #if !defined(THREAD_PROFILER)
  569. class CThreadFastMutex
  570. {
  571. public:
  572. CThreadFastMutex()
  573. : m_ownerID( 0 ),
  574. m_depth( 0 )
  575. {
  576. }
  577. private:
  578. FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile
  579. {
  580. if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile long *)&m_ownerID, (long)threadId, 0 ) )
  581. return false;
  582. ThreadMemoryBarrier();
  583. ++m_depth;
  584. return true;
  585. }
  586. bool TryLock( const uint32 threadId ) volatile
  587. {
  588. return TryLockInline( threadId );
  589. }
  590. PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile;
  591. public:
  592. bool TryLock() volatile
  593. {
  594. #ifdef _DEBUG
  595. if ( m_depth == INT_MAX )
  596. DebuggerBreak();
  597. if ( m_depth < 0 )
  598. DebuggerBreak();
  599. #endif
  600. return TryLockInline( ThreadGetCurrentId() );
  601. }
  602. #ifndef _DEBUG
  603. FORCEINLINE
  604. #endif
  605. void Lock( unsigned int nSpinSleepTime = 0 ) volatile
  606. {
  607. const uint32 threadId = ThreadGetCurrentId();
  608. if ( !TryLockInline( threadId ) )
  609. {
  610. ThreadPause();
  611. Lock( threadId, nSpinSleepTime );
  612. }
  613. #ifdef _DEBUG
  614. if ( m_ownerID != ThreadGetCurrentId() )
  615. DebuggerBreak();
  616. if ( m_depth == INT_MAX )
  617. DebuggerBreak();
  618. if ( m_depth < 0 )
  619. DebuggerBreak();
  620. #endif
  621. }
  622. #ifndef _DEBUG
  623. FORCEINLINE
  624. #endif
  625. void Unlock() volatile
  626. {
  627. #ifdef _DEBUG
  628. if ( m_ownerID != ThreadGetCurrentId() )
  629. DebuggerBreak();
  630. if ( m_depth <= 0 )
  631. DebuggerBreak();
  632. #endif
  633. --m_depth;
  634. if ( !m_depth )
  635. {
  636. ThreadMemoryBarrier();
  637. ThreadInterlockedExchange( &m_ownerID, 0 );
  638. }
  639. }
  640. #ifdef WIN32
  641. bool TryLock() const volatile { return (const_cast<CThreadFastMutex *>(this))->TryLock(); }
  642. void Lock(unsigned nSpinSleepTime = 1 ) const volatile { (const_cast<CThreadFastMutex *>(this))->Lock( nSpinSleepTime ); }
  643. void Unlock() const volatile { (const_cast<CThreadFastMutex *>(this))->Unlock(); }
  644. #endif
  645. // To match regular CThreadMutex:
  646. bool AssertOwnedByCurrentThread() { return true; }
  647. void SetTrace( bool ) {}
  648. uint32 GetOwnerId() const { return m_ownerID; }
  649. int GetDepth() const { return m_depth; }
  650. private:
  651. volatile uint32 m_ownerID;
  652. int m_depth;
  653. };
  654. #ifdef COMPILER_CLANG
  655. # pragma clang diagnostic push
  656. # pragma clang diagnostic ignored "-Wunused-private-field"
  657. #endif // Q_CC_CLANG
  658. class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex
  659. {
  660. public:
  661. CAlignedThreadFastMutex()
  662. {
  663. Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 );
  664. }
  665. private:
  666. uint8 pad[128-sizeof(CThreadFastMutex)];
  667. } ALIGN128_POST;
  668. #ifdef COMPILER_CLANG
  669. # pragma clang diagnostic pop
  670. #endif
  671. #else
  672. typedef CThreadMutex CThreadFastMutex;
  673. #endif
  674. //-----------------------------------------------------------------------------
  675. //
  676. //-----------------------------------------------------------------------------
  677. class CThreadNullMutex
  678. {
  679. public:
  680. static void Lock() {}
  681. static void Unlock() {}
  682. static bool TryLock() { return true; }
  683. static bool AssertOwnedByCurrentThread() { return true; }
  684. static void SetTrace( bool b ) {}
  685. static uint32 GetOwnerId() { return 0; }
  686. static int GetDepth() { return 0; }
  687. };
  688. //-----------------------------------------------------------------------------
  689. //
  690. // A mutex decorator class used to control the use of a mutex, to make it
  691. // less expensive when not multithreading
  692. //
  693. //-----------------------------------------------------------------------------
  694. template <class BaseClass, bool *pCondition>
  695. class CThreadConditionalMutex : public BaseClass
  696. {
  697. public:
  698. void Lock() { if ( *pCondition ) BaseClass::Lock(); }
  699. void Lock() const { if ( *pCondition ) BaseClass::Lock(); }
  700. void Unlock() { if ( *pCondition ) BaseClass::Unlock(); }
  701. void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); }
  702. bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; }
  703. bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; }
  704. bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; }
  705. void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); }
  706. };
  707. //-----------------------------------------------------------------------------
  708. // Mutex decorator that blows up if another thread enters
  709. //-----------------------------------------------------------------------------
  710. template <class BaseClass>
  711. class CThreadTerminalMutex : public BaseClass
  712. {
  713. public:
  714. bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
  715. bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
  716. void Lock() { if ( !TryLock() ) BaseClass::Lock(); }
  717. void Lock() const { if ( !TryLock() ) BaseClass::Lock(); }
  718. };
  719. //-----------------------------------------------------------------------------
  720. //
  721. // Class to Lock a critical section, and unlock it automatically
  722. // when the lock goes out of scope
  723. //
  724. //-----------------------------------------------------------------------------
  725. template <class MUTEX_TYPE = CThreadMutex>
  726. class CAutoLockT
  727. {
  728. public:
  729. FORCEINLINE CAutoLockT( MUTEX_TYPE &lock, const char* pMutexName, const char* pFilename, int nLineNum, uint64 minReportDurationUs )
  730. : m_lock( const_cast< typename V_remove_const< MUTEX_TYPE >::type & >( lock ) )
  731. , m_pMutexName( pMutexName )
  732. , m_pFilename( pFilename )
  733. , m_nLineNum( nLineNum )
  734. , m_bOwned( true )
  735. {
  736. tmTryLockEx( TELEMETRY_LEVEL0, &m_uLockMatcher, minReportDurationUs, pFilename, nLineNum, &m_lock, pMutexName );
  737. m_lock.Lock();
  738. tmEndTryLockEx( TELEMETRY_LEVEL0, m_uLockMatcher, pFilename, nLineNum, &m_lock, TMLR_SUCCESS );
  739. tmSetLockStateEx( TELEMETRY_LEVEL0, pFilename, nLineNum, &m_lock, TMLS_LOCKED, pMutexName );
  740. }
  741. FORCEINLINE CAutoLockT<MUTEX_TYPE>( CAutoLockT<MUTEX_TYPE> && rhs )
  742. : m_lock( const_cast< typename V_remove_const< MUTEX_TYPE >::type &>( rhs.m_lock ) )
  743. {
  744. m_pMutexName = rhs.m_pMutexName;
  745. m_pFilename = rhs.m_pFilename;
  746. m_nLineNum = rhs.m_nLineNum;
  747. #ifdef RAD_TELEMETRY_ENABLED
  748. m_uLockMatcher = rhs.m_uLockMatcher;
  749. #endif
  750. m_bOwned = true;
  751. rhs.m_bOwned = false;
  752. }
  753. FORCEINLINE ~CAutoLockT()
  754. {
  755. if ( m_bOwned )
  756. {
  757. m_lock.Unlock();
  758. tmSetLockStateEx( TELEMETRY_LEVEL0, m_pFilename, m_nLineNum, &m_lock, TMLS_RELEASED, m_pMutexName );
  759. }
  760. }
  761. private:
  762. typename V_remove_const< MUTEX_TYPE >::type &m_lock;
  763. const char* m_pMutexName;
  764. const char* m_pFilename;
  765. int m_nLineNum;
  766. bool m_bOwned; // Did owenership of the lock pass to another instance?
  767. #ifdef RAD_TELEMETRY_ENABLED
  768. TmU64 m_uLockMatcher;
  769. #endif
  770. // Disallow copying
  771. CAutoLockT<MUTEX_TYPE>( const CAutoLockT<MUTEX_TYPE> & );
  772. CAutoLockT<MUTEX_TYPE> &operator=( const CAutoLockT<MUTEX_TYPE> & );
  773. // No move assignment because no default construction.
  774. CAutoLockT<MUTEX_TYPE> &operator=( CAutoLockT<MUTEX_TYPE> && );
  775. };
  776. typedef CAutoLockT<CThreadMutex> CAutoLock;
  777. template < typename MUTEX_TYPE >
  778. inline CAutoLockT<MUTEX_TYPE> make_auto_lock( MUTEX_TYPE& lock, const char* pMutexname, const char* pFilename, int nLineNum, int nMinReportDurationUs = 1 )
  779. {
  780. return CAutoLockT<MUTEX_TYPE>( lock, pMutexname, pFilename, nLineNum, nMinReportDurationUs );
  781. }
  782. //---------------------------------------------------------
  783. #define AUTO_LOCK( mutex ) \
  784. auto UNIQUE_ID = make_auto_lock( mutex, #mutex, __FILE__, __LINE__ );
  785. #define AUTO_LOCK_D( mutex, minDurationUs ) \
  786. auto UNIQUE_ID = make_auto_lock( mutex, #mutex, __FILE__, __LINE__, minDurationUs );
  787. #define LOCAL_THREAD_LOCK_( tag ) \
  788. ; \
  789. static CThreadFastMutex autoMutex_##tag; \
  790. AUTO_LOCK( autoMutex_##tag )
  791. #define LOCAL_THREAD_LOCK() \
  792. LOCAL_THREAD_LOCK_(_)
  793. //-----------------------------------------------------------------------------
  794. //
  795. // Base class for event, semaphore and mutex objects.
  796. //
  797. //-----------------------------------------------------------------------------
  798. class PLATFORM_CLASS CThreadSyncObject
  799. {
  800. public:
  801. ~CThreadSyncObject();
  802. //-----------------------------------------------------
  803. // Query if object is useful
  804. //-----------------------------------------------------
  805. bool operator!() const;
  806. //-----------------------------------------------------
  807. // Access handle
  808. //-----------------------------------------------------
  809. #ifdef _WIN32
  810. operator HANDLE() { return GetHandle(); }
  811. const HANDLE GetHandle() const { return m_hSyncObject; }
  812. #endif
  813. //-----------------------------------------------------
  814. // Wait for a signal from the object
  815. //-----------------------------------------------------
  816. bool Wait( uint32 dwTimeout = TT_INFINITE );
  817. protected:
  818. CThreadSyncObject();
  819. void AssertUseable();
  820. #ifdef _WIN32
  821. HANDLE m_hSyncObject;
  822. bool m_bCreatedHandle;
  823. #elif defined(POSIX)
  824. pthread_mutex_t m_Mutex;
  825. pthread_cond_t m_Condition;
  826. bool m_bInitalized;
  827. int m_cSet;
  828. bool m_bManualReset;
  829. bool m_bWakeForEvent;
  830. #else
  831. #error "Implement me"
  832. #endif
  833. private:
  834. CThreadSyncObject( const CThreadSyncObject & );
  835. CThreadSyncObject &operator=( const CThreadSyncObject & );
  836. };
  837. //-----------------------------------------------------------------------------
  838. //
  839. // Wrapper for unnamed event objects
  840. //
  841. //-----------------------------------------------------------------------------
  842. #if defined( _WIN32 )
  843. //-----------------------------------------------------------------------------
  844. //
  845. // CThreadSemaphore
  846. //
  847. //-----------------------------------------------------------------------------
  848. class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject
  849. {
  850. public:
  851. CThreadSemaphore(long initialValue, long maxValue);
  852. //-----------------------------------------------------
  853. // Increases the count of the semaphore object by a specified
  854. // amount. Wait() decreases the count by one on return.
  855. //-----------------------------------------------------
  856. bool Release(long releaseCount = 1, long * pPreviousCount = NULL );
  857. private:
  858. CThreadSemaphore(const CThreadSemaphore &);
  859. CThreadSemaphore &operator=(const CThreadSemaphore &);
  860. };
  861. //-----------------------------------------------------------------------------
  862. //
  863. // A mutex suitable for out-of-process, multi-processor usage
  864. //
  865. //-----------------------------------------------------------------------------
  866. class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject
  867. {
  868. public:
  869. CThreadFullMutex( bool bEstablishInitialOwnership = false, const char * pszName = NULL );
  870. //-----------------------------------------------------
  871. // Release ownership of the mutex
  872. //-----------------------------------------------------
  873. bool Release();
  874. // To match regular CThreadMutex:
  875. void Lock() { Wait(); }
  876. void Lock( unsigned timeout ) { Wait( timeout ); }
  877. void Unlock() { Release(); }
  878. bool AssertOwnedByCurrentThread() { return true; }
  879. void SetTrace( bool ) {}
  880. private:
  881. CThreadFullMutex( const CThreadFullMutex & );
  882. CThreadFullMutex &operator=( const CThreadFullMutex & );
  883. };
  884. #endif
  885. class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject
  886. {
  887. public:
  888. CThreadEvent( bool fManualReset = false );
  889. #ifdef WIN32
  890. CThreadEvent( HANDLE hHandle );
  891. #endif
  892. //-----------------------------------------------------
  893. // Set the state to signaled
  894. //-----------------------------------------------------
  895. bool Set();
  896. //-----------------------------------------------------
  897. // Set the state to nonsignaled
  898. //-----------------------------------------------------
  899. bool Reset();
  900. //-----------------------------------------------------
  901. // Check if the event is signaled
  902. //-----------------------------------------------------
  903. bool Check();
  904. bool Wait( uint32 dwTimeout = TT_INFINITE );
  905. private:
  906. CThreadEvent( const CThreadEvent & );
  907. CThreadEvent &operator=( const CThreadEvent & );
  908. };
  909. // Hard-wired manual event for use in array declarations
  910. class CThreadManualEvent : public CThreadEvent
  911. {
  912. public:
  913. CThreadManualEvent()
  914. : CThreadEvent( true )
  915. {
  916. }
  917. };
  918. inline int ThreadWaitForEvents( int nEvents, CThreadEvent * const *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE )
  919. {
  920. #ifdef POSIX
  921. Assert( nEvents == 1);
  922. if ( pEvents[0]->Wait( timeout ) )
  923. return WAIT_OBJECT_0;
  924. else
  925. return WAIT_TIMEOUT;
  926. #else
  927. HANDLE handles[64];
  928. for ( int i = 0; i < min( nEvents, (int)ARRAYSIZE(handles) ); i++ )
  929. handles[i] = pEvents[i]->GetHandle();
  930. return ThreadWaitForObjects( nEvents, handles, bWaitAll, timeout );
  931. #endif
  932. }
  933. //-----------------------------------------------------------------------------
  934. //
  935. // CThreadRWLock
  936. //
  937. //-----------------------------------------------------------------------------
  938. class PLATFORM_CLASS CThreadRWLock
  939. {
  940. public:
  941. CThreadRWLock();
  942. void LockForRead();
  943. void UnlockRead();
  944. void LockForWrite();
  945. void UnlockWrite();
  946. void LockForRead() const { const_cast<CThreadRWLock *>(this)->LockForRead(); }
  947. void UnlockRead() const { const_cast<CThreadRWLock *>(this)->UnlockRead(); }
  948. void LockForWrite() const { const_cast<CThreadRWLock *>(this)->LockForWrite(); }
  949. void UnlockWrite() const { const_cast<CThreadRWLock *>(this)->UnlockWrite(); }
  950. private:
  951. void WaitForRead();
  952. #ifdef WIN32
  953. CThreadFastMutex m_mutex;
  954. #else
  955. CThreadMutex m_mutex;
  956. #endif
  957. CThreadEvent m_CanWrite;
  958. CThreadEvent m_CanRead;
  959. int m_nWriters;
  960. int m_nActiveReaders;
  961. int m_nPendingReaders;
  962. };
  963. //-----------------------------------------------------------------------------
  964. //
  965. // CThreadSpinRWLock
  966. //
  967. //-----------------------------------------------------------------------------
  968. class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock
  969. {
  970. public:
  971. CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); }
  972. bool TryLockForWrite();
  973. bool TryLockForRead();
  974. void LockForRead();
  975. void UnlockRead();
  976. void LockForWrite();
  977. void UnlockWrite();
  978. bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); }
  979. bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); }
  980. void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); }
  981. void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); }
  982. void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); }
  983. void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); }
  984. private:
  985. struct LockInfo_t
  986. {
  987. uint32 m_writerId;
  988. int m_nReaders;
  989. };
  990. bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand );
  991. bool TryLockForWrite( const uint32 threadId );
  992. void SpinLockForWrite( const uint32 threadId );
  993. volatile LockInfo_t m_lockInfo;
  994. CInterlockedInt m_nWriters;
  995. } ALIGN8_POST;
  996. //-----------------------------------------------------------------------------
  997. //
  998. // A thread wrapper similar to a Java thread.
  999. //
  1000. //-----------------------------------------------------------------------------
  1001. class PLATFORM_CLASS CThread
  1002. {
  1003. public:
  1004. CThread();
  1005. virtual ~CThread();
  1006. //-----------------------------------------------------
  1007. const char *GetName();
  1008. void SetName( const char * );
  1009. size_t CalcStackDepth( void *pStackVariable ) { return ((byte *)m_pStackBase - (byte *)pStackVariable); }
  1010. //-----------------------------------------------------
  1011. // Functions for the other threads
  1012. //-----------------------------------------------------
  1013. // Start thread running - error if already running
  1014. virtual bool Start( unsigned nBytesStack = 0 );
  1015. // Returns true if thread has been created and hasn't yet exited
  1016. bool IsAlive();
  1017. // This method causes the current thread to wait until this thread
  1018. // is no longer alive.
  1019. bool Join( unsigned timeout = TT_INFINITE );
  1020. #ifdef _WIN32
  1021. // Access the thread handle directly
  1022. HANDLE GetThreadHandle();
  1023. uint GetThreadId();
  1024. #elif defined( LINUX )
  1025. uint GetThreadId();
  1026. #endif
  1027. //-----------------------------------------------------
  1028. int GetResult();
  1029. //-----------------------------------------------------
  1030. // Functions for both this, and maybe, and other threads
  1031. //-----------------------------------------------------
  1032. // Forcibly, abnormally, but relatively cleanly stop the thread
  1033. void Stop( int exitCode = 0 );
  1034. // Get the priority
  1035. int GetPriority() const;
  1036. // Set the priority
  1037. bool SetPriority( int );
  1038. // Request a thread to suspend, this must ONLY be called from the thread itself, not the main thread
  1039. // This suspend variant causes the thread in question to suspend at a known point in its execution
  1040. // which means you don't risk the global deadlocks/hangs potentially caused by the raw Suspend() call
  1041. void SuspendCooperative();
  1042. // Resume a previously suspended thread from the Cooperative call
  1043. void ResumeCooperative();
  1044. // wait for a thread to execute its SuspendCooperative call
  1045. void BWaitForThreadSuspendCooperative();
  1046. #ifndef LINUX
  1047. // forcefully Suspend a thread
  1048. unsigned int Suspend();
  1049. // forcefully Resume a previously suspended thread
  1050. unsigned int Resume();
  1051. #endif
  1052. // Force hard-termination of thread. Used for critical failures.
  1053. bool Terminate( int exitCode = 0 );
  1054. //-----------------------------------------------------
  1055. // Global methods
  1056. //-----------------------------------------------------
  1057. // Get the Thread object that represents the current thread, if any.
  1058. // Can return NULL if the current thread was not created using
  1059. // CThread
  1060. static CThread *GetCurrentCThread();
  1061. // Offer a context switch. Under Win32, equivalent to Sleep(0)
  1062. #ifdef Yield
  1063. #undef Yield
  1064. #endif
  1065. static void Yield();
  1066. // This method causes the current thread to yield and not to be
  1067. // scheduled for further execution until a certain amount of real
  1068. // time has elapsed, more or less.
  1069. static void Sleep( unsigned duration );
  1070. protected:
  1071. // Optional pre-run call, with ability to fail-create. Note Init()
  1072. // is forced synchronous with Start()
  1073. virtual bool Init();
  1074. // Thread will run this function on startup, must be supplied by
  1075. // derived class, performs the intended action of the thread.
  1076. virtual int Run() = 0;
  1077. // Called when the thread is about to exit, by the about-to-exit thread.
  1078. virtual void OnExit();
  1079. // Called after OnExit when a thread finishes or is killed. Not virtual because no inherited classes
  1080. // override it and we don't want to change the vtable from the published SDK version.
  1081. void Cleanup();
  1082. bool WaitForCreateComplete( CThreadEvent *pEvent );
  1083. // "Virtual static" facility
  1084. typedef unsigned (__stdcall *ThreadProc_t)( void * );
  1085. virtual ThreadProc_t GetThreadProc();
  1086. virtual bool IsThreadRunning();
  1087. CThreadMutex m_Lock;
  1088. #ifdef WIN32
  1089. ThreadHandle_t GetThreadID() const { return (ThreadHandle_t)m_hThread; }
  1090. #else
  1091. ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; }
  1092. #endif
  1093. private:
  1094. enum Flags
  1095. {
  1096. SUPPORT_STOP_PROTOCOL = 1 << 0
  1097. };
  1098. // Thread initially runs this. param is actually 'this'. function
  1099. // just gets this and calls ThreadProc
  1100. struct ThreadInit_t
  1101. {
  1102. CThread * pThread;
  1103. CThreadEvent *pInitCompleteEvent;
  1104. bool * pfInitSuccess;
  1105. };
  1106. static unsigned __stdcall ThreadProc( void * pv );
  1107. // make copy constructor and assignment operator inaccessible
  1108. CThread( const CThread & );
  1109. CThread &operator=( const CThread & );
  1110. #ifdef _WIN32
  1111. HANDLE m_hThread;
  1112. ThreadId_t m_threadId;
  1113. #elif defined(POSIX)
  1114. pthread_t m_threadId;
  1115. #endif
  1116. CInterlockedInt m_nSuspendCount;
  1117. CThreadEvent m_SuspendEvent;
  1118. CThreadEvent m_SuspendEventSignal;
  1119. int m_result;
  1120. char m_szName[32];
  1121. void * m_pStackBase;
  1122. unsigned m_flags;
  1123. };
  1124. //-----------------------------------------------------------------------------
  1125. //
  1126. // A helper class to let you sleep a thread for memory validation, you need to handle
  1127. // m_bSleepForValidate in your ::Run() call and set m_bSleepingForValidate when sleeping
  1128. //
  1129. //-----------------------------------------------------------------------------
  1130. class PLATFORM_CLASS CValidatableThread : public CThread
  1131. {
  1132. public:
  1133. CValidatableThread()
  1134. {
  1135. m_bSleepForValidate = false;
  1136. m_bSleepingForValidate = false;
  1137. }
  1138. #ifdef DBGFLAG_VALIDATE
  1139. virtual void SleepForValidate() { m_bSleepForValidate = true; }
  1140. bool BSleepingForValidate() { return m_bSleepingForValidate; }
  1141. virtual void WakeFromValidate() { m_bSleepForValidate = false; }
  1142. #endif
  1143. protected:
  1144. bool m_bSleepForValidate;
  1145. bool m_bSleepingForValidate;
  1146. };
  1147. //-----------------------------------------------------------------------------
  1148. // Simple thread class encompasses the notion of a worker thread, handing
  1149. // synchronized communication.
  1150. //-----------------------------------------------------------------------------
  1151. // These are internal reserved error results from a call attempt
  1152. enum WTCallResult_t
  1153. {
  1154. WTCR_FAIL = -1,
  1155. WTCR_TIMEOUT = -2,
  1156. WTCR_THREAD_GONE = -3,
  1157. };
  1158. class CFunctor;
  1159. class PLATFORM_CLASS CWorkerThread : public CThread
  1160. {
  1161. public:
  1162. CWorkerThread();
  1163. //-----------------------------------------------------
  1164. //
  1165. // Inter-thread communication
  1166. //
  1167. // Calls in either direction take place on the same "channel."
  1168. // Seperate functions are specified to make identities obvious
  1169. //
  1170. //-----------------------------------------------------
  1171. // Master: Signal the thread, and block for a response
  1172. int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true, CFunctor *pParamFunctor = NULL );
  1173. // Worker: Signal the thread, and block for a response
  1174. int CallMaster( unsigned, unsigned timeout = TT_INFINITE );
  1175. // Wait for the next request
  1176. bool WaitForCall( unsigned dwTimeout, unsigned *pResult = NULL );
  1177. bool WaitForCall( unsigned *pResult = NULL );
  1178. // Is there a request?
  1179. bool PeekCall( unsigned *pParam = NULL, CFunctor **ppParamFunctor = NULL );
  1180. // Reply to the request
  1181. void Reply( unsigned );
  1182. // Wait for a reply in the case when CallWorker() with timeout != TT_INFINITE
  1183. int WaitForReply( unsigned timeout = TT_INFINITE );
  1184. // If you want to do WaitForMultipleObjects you'll need to include
  1185. // this handle in your wait list or you won't be responsive
  1186. CThreadEvent &GetCallHandle();
  1187. // Find out what the request was
  1188. unsigned GetCallParam( CFunctor **ppParamFunctor = NULL ) const;
  1189. // Boost the worker thread to the master thread, if worker thread is lesser, return old priority
  1190. int BoostPriority();
  1191. protected:
  1192. #ifndef _WIN32
  1193. #define __stdcall
  1194. #endif
  1195. typedef uint32 (__stdcall *WaitFunc_t)( int nEvents, CThreadEvent * const *pEvents, int bWaitAll, uint32 timeout );
  1196. int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL, CFunctor *pParamFunctor = NULL );
  1197. int WaitForReply( unsigned timeout, WaitFunc_t );
  1198. private:
  1199. CWorkerThread( const CWorkerThread & );
  1200. CWorkerThread &operator=( const CWorkerThread & );
  1201. CThreadEvent m_EventSend;
  1202. CThreadEvent m_EventComplete;
  1203. unsigned m_Param;
  1204. CFunctor *m_pParamFunctor;
  1205. int m_ReturnVal;
  1206. };
  1207. // a unidirectional message queue. A queue of type T. Not especially high speed since each message
  1208. // is malloced/freed. Note that if your message class has destructors/constructors, they MUST be
  1209. // thread safe!
  1210. template<class T> class CMessageQueue
  1211. {
  1212. CThreadEvent SignalEvent; // signals presence of data
  1213. CThreadMutex QueueAccessMutex;
  1214. // the parts protected by the mutex
  1215. struct MsgNode
  1216. {
  1217. MsgNode *Next;
  1218. T Data;
  1219. };
  1220. MsgNode *Head;
  1221. MsgNode *Tail;
  1222. public:
  1223. CMessageQueue( void )
  1224. {
  1225. Head = Tail = NULL;
  1226. }
  1227. // check for a message. not 100% reliable - someone could grab the message first
  1228. bool MessageWaiting( void )
  1229. {
  1230. return ( Head != NULL );
  1231. }
  1232. void WaitMessage( T *pMsg )
  1233. {
  1234. for(;;)
  1235. {
  1236. while( ! MessageWaiting() )
  1237. SignalEvent.Wait();
  1238. QueueAccessMutex.Lock();
  1239. if (! Head )
  1240. {
  1241. // multiple readers could make this null
  1242. QueueAccessMutex.Unlock();
  1243. continue;
  1244. }
  1245. *( pMsg ) = Head->Data;
  1246. MsgNode *remove_this = Head;
  1247. Head = Head->Next;
  1248. if (! Head) // if empty, fix tail ptr
  1249. Tail = NULL;
  1250. QueueAccessMutex.Unlock();
  1251. delete remove_this;
  1252. break;
  1253. }
  1254. }
  1255. void QueueMessage( T const &Msg)
  1256. {
  1257. MsgNode *new1=new MsgNode;
  1258. new1->Data=Msg;
  1259. new1->Next=NULL;
  1260. QueueAccessMutex.Lock();
  1261. if ( Tail )
  1262. {
  1263. Tail->Next=new1;
  1264. Tail = new1;
  1265. }
  1266. else
  1267. {
  1268. Head = new1;
  1269. Tail = new1;
  1270. }
  1271. SignalEvent.Set();
  1272. QueueAccessMutex.Unlock();
  1273. }
  1274. };
  1275. //-----------------------------------------------------------------------------
  1276. //
  1277. // CThreadMutex. Inlining to reduce overhead and to allow client code
  1278. // to decide debug status (tracing)
  1279. //
  1280. //-----------------------------------------------------------------------------
  1281. #ifdef _WIN32
  1282. typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION;
  1283. typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
  1284. #ifndef _X360
  1285. extern "C"
  1286. {
  1287. void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION *);
  1288. void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION *);
  1289. void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION *);
  1290. void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION *);
  1291. };
  1292. #endif
  1293. //---------------------------------------------------------
  1294. inline void CThreadMutex::Lock()
  1295. {
  1296. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1297. uint thisThreadID = ThreadGetCurrentId();
  1298. if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) )
  1299. Msg( "Thread %u about to wait for lock %p owned by %u\n", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
  1300. #endif
  1301. VCRHook_EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection);
  1302. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1303. if (m_lockCount == 0)
  1304. {
  1305. // we now own it for the first time. Set owner information
  1306. m_currentOwnerID = thisThreadID;
  1307. if ( m_bTrace )
  1308. Msg( "Thread %u now owns lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
  1309. }
  1310. m_lockCount++;
  1311. #endif
  1312. }
  1313. //---------------------------------------------------------
  1314. inline void CThreadMutex::Unlock()
  1315. {
  1316. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1317. AssertMsg( m_lockCount >= 1, "Invalid unlock of thread lock" );
  1318. m_lockCount--;
  1319. if (m_lockCount == 0)
  1320. {
  1321. if ( m_bTrace )
  1322. Msg( "Thread %u releasing lock %p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
  1323. m_currentOwnerID = 0;
  1324. }
  1325. #endif
  1326. LeaveCriticalSection((CRITICAL_SECTION *)&m_CriticalSection);
  1327. }
  1328. //---------------------------------------------------------
  1329. inline bool CThreadMutex::AssertOwnedByCurrentThread()
  1330. {
  1331. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1332. if (ThreadGetCurrentId() == m_currentOwnerID)
  1333. return true;
  1334. AssertMsg3( 0, "Expected thread %u as owner of lock %p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
  1335. return false;
  1336. #else
  1337. return true;
  1338. #endif
  1339. }
  1340. //---------------------------------------------------------
  1341. inline void CThreadMutex::SetTrace( bool bTrace )
  1342. {
  1343. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1344. m_bTrace = bTrace;
  1345. #endif
  1346. }
  1347. //---------------------------------------------------------
  1348. #elif defined(POSIX)
  1349. inline CThreadMutex::CThreadMutex()
  1350. {
  1351. // enable recursive locks as we need them
  1352. pthread_mutexattr_init( &m_Attr );
  1353. pthread_mutexattr_settype( &m_Attr, PTHREAD_MUTEX_RECURSIVE );
  1354. pthread_mutex_init( &m_Mutex, &m_Attr );
  1355. }
  1356. //---------------------------------------------------------
  1357. inline CThreadMutex::~CThreadMutex()
  1358. {
  1359. pthread_mutex_destroy( &m_Mutex );
  1360. }
  1361. //---------------------------------------------------------
  1362. inline void CThreadMutex::Lock()
  1363. {
  1364. pthread_mutex_lock( &m_Mutex );
  1365. }
  1366. //---------------------------------------------------------
  1367. inline void CThreadMutex::Unlock()
  1368. {
  1369. pthread_mutex_unlock( &m_Mutex );
  1370. }
  1371. //---------------------------------------------------------
  1372. inline bool CThreadMutex::AssertOwnedByCurrentThread()
  1373. {
  1374. return true;
  1375. }
  1376. //---------------------------------------------------------
  1377. inline void CThreadMutex::SetTrace(bool fTrace)
  1378. {
  1379. }
  1380. #endif // POSIX
  1381. //-----------------------------------------------------------------------------
  1382. //
  1383. // CThreadRWLock inline functions
  1384. //
  1385. //-----------------------------------------------------------------------------
  1386. inline CThreadRWLock::CThreadRWLock()
  1387. : m_CanRead( true ),
  1388. m_nWriters( 0 ),
  1389. m_nActiveReaders( 0 ),
  1390. m_nPendingReaders( 0 )
  1391. {
  1392. }
  1393. inline void CThreadRWLock::LockForRead()
  1394. {
  1395. m_mutex.Lock();
  1396. if ( m_nWriters)
  1397. {
  1398. WaitForRead();
  1399. }
  1400. m_nActiveReaders++;
  1401. m_mutex.Unlock();
  1402. }
  1403. inline void CThreadRWLock::UnlockRead()
  1404. {
  1405. m_mutex.Lock();
  1406. m_nActiveReaders--;
  1407. if ( m_nActiveReaders == 0 && m_nWriters != 0 )
  1408. {
  1409. m_CanWrite.Set();
  1410. }
  1411. m_mutex.Unlock();
  1412. }
  1413. //-----------------------------------------------------------------------------
  1414. //
  1415. // CThreadSpinRWLock inline functions
  1416. //
  1417. //-----------------------------------------------------------------------------
  1418. inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand )
  1419. {
  1420. return ThreadInterlockedAssignIf64( (int64 *)&m_lockInfo, *((int64 *)&newValue), *((int64 *)&comperand) );
  1421. }
  1422. inline bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId )
  1423. {
  1424. // In order to grab a write lock, there can be no readers and no owners of the write lock
  1425. if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) )
  1426. {
  1427. return false;
  1428. }
  1429. static const LockInfo_t oldValue = { 0, 0 };
  1430. LockInfo_t newValue = { threadId, 0 };
  1431. const bool bSuccess = AssignIf( newValue, oldValue );
  1432. #if defined(_X360)
  1433. if ( bSuccess )
  1434. {
  1435. // X360TBD: Serious perf implications. Not Yet. __sync();
  1436. }
  1437. #endif
  1438. return bSuccess;
  1439. }
  1440. inline bool CThreadSpinRWLock::TryLockForWrite()
  1441. {
  1442. m_nWriters++;
  1443. if ( !TryLockForWrite( ThreadGetCurrentId() ) )
  1444. {
  1445. m_nWriters--;
  1446. return false;
  1447. }
  1448. return true;
  1449. }
  1450. inline bool CThreadSpinRWLock::TryLockForRead()
  1451. {
  1452. if ( m_nWriters != 0 )
  1453. {
  1454. return false;
  1455. }
  1456. // In order to grab a write lock, the number of readers must not change and no thread can own the write
  1457. LockInfo_t oldValue;
  1458. LockInfo_t newValue;
  1459. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1460. oldValue.m_writerId = 0;
  1461. newValue.m_nReaders = oldValue.m_nReaders + 1;
  1462. newValue.m_writerId = 0;
  1463. const bool bSuccess = AssignIf( newValue, oldValue );
  1464. #if defined(_X360)
  1465. if ( bSuccess )
  1466. {
  1467. // X360TBD: Serious perf implications. Not Yet. __sync();
  1468. }
  1469. #endif
  1470. return bSuccess;
  1471. }
  1472. inline void CThreadSpinRWLock::LockForWrite()
  1473. {
  1474. const uint32 threadId = ThreadGetCurrentId();
  1475. m_nWriters++;
  1476. if ( !TryLockForWrite( threadId ) )
  1477. {
  1478. ThreadPause();
  1479. SpinLockForWrite( threadId );
  1480. }
  1481. }
  1482. // read data from a memory address
  1483. template<class T> FORCEINLINE T ReadVolatileMemory( T const *pPtr )
  1484. {
  1485. volatile const T * pVolatilePtr = ( volatile const T * ) pPtr;
  1486. return *pVolatilePtr;
  1487. }
  1488. //-----------------------------------------------------------------------------
  1489. #if defined( _WIN32 )
  1490. #pragma warning(pop)
  1491. #endif
  1492. #endif // THREADTOOLS_H