Counter Strike : Global Offensive Source Code
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.

2636 lines
82 KiB

  1. //========== Copyright 2005, 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 <limits.h>
  11. #include "tier0/platform.h"
  12. #include "tier0/dbg.h"
  13. #if defined( POSIX ) && !defined( _PS3 ) && !defined( _X360 )
  14. #include <pthread.h>
  15. #include <errno.h>
  16. #define WAIT_OBJECT_0 0
  17. #define WAIT_TIMEOUT 0x00000102
  18. #define WAIT_FAILED -1
  19. #define THREAD_PRIORITY_HIGHEST 2
  20. #endif
  21. #if !defined( _X360 ) && !defined( _PS3 ) && defined(COMPILER_MSVC)
  22. // For _ReadWriteBarrier()
  23. #include <intrin.h>
  24. #endif
  25. #if defined( _PS3 )
  26. #include <sys/ppu_thread.h>
  27. #include <sys/synchronization.h>
  28. #include <cell/atomic.h>
  29. #include <sys/timer.h>
  30. #endif
  31. #ifdef OSX
  32. // Add some missing defines
  33. #define PTHREAD_MUTEX_TIMED_NP PTHREAD_MUTEX_NORMAL
  34. #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
  35. #define PTHREAD_MUTEX_ERRORCHECK_NP PTHREAD_MUTEX_ERRORCHECK
  36. #define PTHREAD_MUTEX_ADAPTIVE_NP 3
  37. #endif
  38. #ifdef _PS3
  39. #define PS3_SYS_PPU_THREAD_COMMON_STACK_SIZE ( 256 * 1024 )
  40. #endif
  41. #if defined( _WIN32 )
  42. #pragma once
  43. #pragma warning(push)
  44. #pragma warning(disable:4251)
  45. #endif
  46. #ifdef COMPILER_MSVC64
  47. #include <intrin.h>
  48. #endif
  49. // #define THREAD_PROFILER 1
  50. #define THREAD_MUTEX_TRACING_SUPPORTED
  51. #if defined(_WIN32) && defined(_DEBUG) && !defined(THREAD_MUTEX_TRACING_ENABLED)
  52. #define THREAD_MUTEX_TRACING_ENABLED
  53. #endif
  54. #ifdef _WIN32
  55. typedef void *HANDLE;
  56. #endif
  57. // maximum number of threads that can wait on one object
  58. #define CTHREADEVENT_MAX_WAITING_THREADS 4
  59. // Start thread running - error if already running
  60. enum ThreadPriorityEnum_t
  61. {
  62. #if defined( PLATFORM_PS3 )
  63. TP_PRIORITY_NORMAL = 1001,
  64. TP_PRIORITY_HIGH = 100,
  65. TP_PRIORITY_LOW = 2001,
  66. TP_PRIORITY_DEFAULT = 1001
  67. #error "Need PRIORITY_LOWEST/HIGHEST"
  68. #elif defined( PLATFORM_LINUX )
  69. // We can use nice on Linux threads to change scheduling.
  70. // pthreads on Linux only allows priority setting on
  71. // real-time threads.
  72. // NOTE: Lower numbers are higher priority, thus the need
  73. // for TP_IS_PRIORITY_HIGHER.
  74. TP_PRIORITY_DEFAULT = 0,
  75. TP_PRIORITY_NORMAL = 0,
  76. TP_PRIORITY_HIGH = -10,
  77. TP_PRIORITY_LOW = 10,
  78. TP_PRIORITY_HIGHEST = -20,
  79. TP_PRIORITY_LOWEST = 19,
  80. #else // PLATFORM_PS3
  81. TP_PRIORITY_DEFAULT = 0, // THREAD_PRIORITY_NORMAL
  82. TP_PRIORITY_NORMAL = 0, // THREAD_PRIORITY_NORMAL
  83. TP_PRIORITY_HIGH = 1, // THREAD_PRIORITY_ABOVE_NORMAL
  84. TP_PRIORITY_LOW = -1, // THREAD_PRIORITY_BELOW_NORMAL
  85. TP_PRIORITY_HIGHEST = 2, // THREAD_PRIORITY_HIGHEST
  86. TP_PRIORITY_LOWEST = -2, // THREAD_PRIORITY_LOWEST
  87. #endif // PLATFORM_PS3
  88. };
  89. #if defined( PLATFORM_LINUX )
  90. #define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) < ( b ) )
  91. #else
  92. #define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) > ( b ) )
  93. #endif
  94. #if (defined( PLATFORM_WINDOWS_PC ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT )
  95. //Thread parent stack trace linkage requires ALL executing binaries to disable frame pointer omission to operate speedily/successfully. (/Oy-) "vpc /nofpo"
  96. #define THREAD_PARENT_STACK_TRACE_SUPPORTED 1 //uncomment to support joining the root of a thread's stack trace to its parent's at time of invocation. Must also set ENABLE_THREAD_PARENT_STACK_TRACING in stacktools.h
  97. #endif
  98. #if defined( THREAD_PARENT_STACK_TRACE_SUPPORTED )
  99. #include "tier0/stacktools.h"
  100. # if defined( ENABLE_THREAD_PARENT_STACK_TRACING ) //stacktools.h opted in
  101. # define THREAD_PARENT_STACK_TRACE_ENABLED 1 //both threadtools.h and stacktools.h have opted into the feature, enable it
  102. # endif
  103. #endif
  104. extern bool gbCheckNotMultithreaded;
  105. #ifdef _PS3
  106. #define USE_INTRINSIC_INTERLOCKED
  107. #define CHECK_NOT_MULTITHREADED() \
  108. { \
  109. static int init = 0; \
  110. static sys_ppu_thread_t threadIDPrev; \
  111. \
  112. if (!init) \
  113. { \
  114. sys_ppu_thread_get_id(&threadIDPrev); \
  115. init = 1; \
  116. } \
  117. else if (gbCheckNotMultithreaded) \
  118. { \
  119. sys_ppu_thread_t threadID; \
  120. sys_ppu_thread_get_id(&threadID); \
  121. if (threadID != threadIDPrev) \
  122. { \
  123. printf("CHECK_NOT_MULTITHREADED: prev thread = %x, cur thread = %x\n", \
  124. (uint)threadIDPrev, (uint)threadID); \
  125. *(int*)0 = 0; \
  126. } \
  127. } \
  128. }
  129. #else // _PS3
  130. #define CHECK_NOT_MULTITHREADED()
  131. #endif // _PS3
  132. #if defined( _X360 ) || defined( _PS3 )
  133. #define MAX_THREADS_SUPPORTED 16
  134. #else
  135. #define MAX_THREADS_SUPPORTED 32
  136. #endif
  137. //-----------------------------------------------------------------------------
  138. //
  139. //-----------------------------------------------------------------------------
  140. const unsigned TT_INFINITE = 0xffffffff;
  141. #ifdef PLATFORM_64BITS
  142. typedef uint64 ThreadId_t;
  143. #else
  144. typedef uint32 ThreadId_t;
  145. #endif
  146. //-----------------------------------------------------------------------------
  147. //
  148. // Simple thread creation. Differs from VCR mode/CreateThread/_beginthreadex
  149. // in that it accepts a standard C function rather than compiler specific one.
  150. //
  151. //-----------------------------------------------------------------------------
  152. #ifdef COMPILER_SNC
  153. typedef uint64 ThreadHandle_t;
  154. #else // COMPILER_SNC
  155. FORWARD_DECLARE_HANDLE( ThreadHandle_t );
  156. #endif // !COMPILER_SNC
  157. typedef uintp (*ThreadFunc_t)( void *pParam );
  158. #if defined( _PS3 )
  159. PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0x10000 /*64*/ );
  160. PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0x10000 /*64*/ );
  161. #else //_PS3
  162. PLATFORM_OVERLOAD ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, ThreadId_t *pID, unsigned stackSize = 0 );
  163. PLATFORM_INTERFACE ThreadHandle_t CreateSimpleThread( ThreadFunc_t, void *pParam, unsigned stackSize = 0 );
  164. #endif //_PS3
  165. PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t );
  166. //-----------------------------------------------------------------------------
  167. PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0);
  168. PLATFORM_INTERFACE void ThreadNanoSleep(unsigned ns);
  169. PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId();
  170. PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle();
  171. PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL );
  172. PLATFORM_INTERFACE bool ThreadSetPriority( ThreadHandle_t hThread, int priority );
  173. inline bool ThreadSetPriority( int priority ) { return ThreadSetPriority( NULL, priority ); }
  174. #ifndef _X360
  175. PLATFORM_INTERFACE bool ThreadInMainThread();
  176. PLATFORM_INTERFACE void DeclareCurrentThreadIsMainThread();
  177. #else
  178. PLATFORM_INTERFACE byte *g_pBaseMainStack;
  179. PLATFORM_INTERFACE byte *g_pLimitMainStack;
  180. inline bool ThreadInMainThread()
  181. {
  182. byte b;
  183. byte *p = &b;
  184. return ( p < g_pBaseMainStack && p >= g_pLimitMainStack );
  185. }
  186. #endif
  187. // NOTE: ThreadedLoadLibraryFunc_t needs to return the sleep time in milliseconds or TT_INFINITE
  188. typedef int (*ThreadedLoadLibraryFunc_t)();
  189. PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func );
  190. PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc();
  191. #if defined( PLATFORM_WINDOWS_PC32 )
  192. DLL_IMPORT unsigned long STDCALL GetCurrentThreadId();
  193. #define ThreadGetCurrentId GetCurrentThreadId
  194. #endif
  195. inline void ThreadPause()
  196. {
  197. #if defined( COMPILER_PS3 )
  198. __db16cyc();
  199. #elif defined( COMPILER_GCC )
  200. __asm __volatile( "pause" );
  201. #elif defined ( COMPILER_MSVC64 )
  202. _mm_pause();
  203. #elif defined( COMPILER_MSVC32 )
  204. __asm pause;
  205. #elif defined( COMPILER_MSVCX360 )
  206. YieldProcessor();
  207. __asm { or r0,r0,r0 }
  208. YieldProcessor();
  209. __asm { or r1,r1,r1 }
  210. #else
  211. #error "implement me"
  212. #endif
  213. }
  214. PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE );
  215. PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName );
  216. inline void ThreadSetDebugName( const char *pszName ) { ThreadSetDebugName( NULL, pszName ); }
  217. PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask );
  218. //-----------------------------------------------------------------------------
  219. //
  220. // Interlock methods. These perform very fast atomic thread
  221. // safe operations. These are especially relevant in a multi-core setting.
  222. //
  223. //-----------------------------------------------------------------------------
  224. #ifdef _WIN32
  225. #define NOINLINE
  226. #elif defined( _PS3 )
  227. #define NOINLINE __attribute__ ((noinline))
  228. #elif defined(POSIX)
  229. #define NOINLINE __attribute__ ((noinline))
  230. #endif
  231. #if defined( _X360 ) || defined( _PS3 )
  232. #define ThreadMemoryBarrier() __lwsync()
  233. #elif defined(COMPILER_MSVC)
  234. // Prevent compiler reordering across this barrier. This is
  235. // sufficient for most purposes on x86/x64.
  236. #define ThreadMemoryBarrier() _ReadWriteBarrier()
  237. #elif defined(COMPILER_GCC)
  238. // Prevent compiler reordering across this barrier. This is
  239. // sufficient for most purposes on x86/x64.
  240. // http://preshing.com/20120625/memory-ordering-at-compile-time
  241. #define ThreadMemoryBarrier() asm volatile("" ::: "memory")
  242. #else
  243. #error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering
  244. #endif
  245. #if defined( _LINUX ) || defined( _OSX )
  246. #define USE_INTRINSIC_INTERLOCKED
  247. // linux implementation
  248. inline int32 ThreadInterlockedIncrement( int32 volatile *p )
  249. {
  250. Assert( (size_t)p % 4 == 0 );
  251. return __sync_fetch_and_add( p, 1 ) + 1;
  252. }
  253. inline int32 ThreadInterlockedDecrement( int32 volatile *p )
  254. {
  255. Assert( (size_t)p % 4 == 0 );
  256. return __sync_fetch_and_add( p, -1 ) - 1;
  257. }
  258. inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value )
  259. {
  260. Assert( (size_t)p % 4 == 0 );
  261. int32 nRet;
  262. // Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it.
  263. __asm __volatile(
  264. "xchgl %2,(%1)"
  265. : "=r" (nRet)
  266. : "r" (p), "0" (value)
  267. : "memory");
  268. return nRet;
  269. }
  270. inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value )
  271. {
  272. Assert( (size_t)p % 4 == 0 );
  273. return __sync_fetch_and_add( p, value );
  274. }
  275. inline int64 ThreadInterlockedExchangeAdd64( int64 volatile *p, int64 value )
  276. {
  277. Assert( ( (size_t)p ) % 8 == 0 );
  278. return __sync_fetch_and_add( p, value );
  279. }
  280. inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand )
  281. {
  282. Assert( (size_t)p % 4 == 0 );
  283. return __sync_val_compare_and_swap( p, comperand, value );
  284. }
  285. inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand )
  286. {
  287. Assert( (size_t)p % 4 == 0 );
  288. return __sync_bool_compare_and_swap( p, comperand, value );
  289. }
  290. #elif ( defined( COMPILER_MSVC32 ) && ( _MSC_VER >= 1310 ) )
  291. // windows 32 implemnetation using compiler intrinsics
  292. #define USE_INTRINSIC_INTERLOCKED
  293. extern "C"
  294. {
  295. long __cdecl _InterlockedIncrement(volatile long*);
  296. long __cdecl _InterlockedDecrement(volatile long*);
  297. long __cdecl _InterlockedExchange(volatile long*, long);
  298. long __cdecl _InterlockedExchangeAdd(volatile long*, long);
  299. long __cdecl _InterlockedCompareExchange(volatile long*, long, long);
  300. }
  301. #pragma intrinsic( _InterlockedCompareExchange )
  302. #pragma intrinsic( _InterlockedDecrement )
  303. #pragma intrinsic( _InterlockedExchange )
  304. #pragma intrinsic( _InterlockedExchangeAdd )
  305. #pragma intrinsic( _InterlockedIncrement )
  306. inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( (volatile long*)p ); }
  307. inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( (volatile long*)p ); }
  308. inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchange( (volatile long*)p, value ); }
  309. inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( (volatile long*)p, value ); }
  310. inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( (volatile long*)p, value, comperand ); }
  311. inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( (volatile long*)p, value, comperand ) == comperand ); }
  312. #elif defined( _PS3 )
  313. PLATFORM_INTERFACE inline int32 ThreadInterlockedIncrement( int32 volatile * ea ) { return cellAtomicIncr32( (uint32_t*)ea ) + 1; }
  314. PLATFORM_INTERFACE inline int32 ThreadInterlockedDecrement( int32 volatile * ea ) { return cellAtomicDecr32( (uint32_t*)ea ) - 1; }
  315. PLATFORM_INTERFACE inline int32 ThreadInterlockedExchange( int32 volatile * ea, int32 value ) { return cellAtomicStore32( ( uint32_t* )ea, value); }
  316. PLATFORM_INTERFACE inline int32 ThreadInterlockedExchangeAdd( int32 volatile * ea, int32 value ) { return cellAtomicAdd32( ( uint32_t* )ea, value ); }
  317. PLATFORM_INTERFACE inline int32 ThreadInterlockedCompareExchange( int32 volatile * ea, int32 value, int32 comperand ) { return cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) ; }
  318. PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf( int32 volatile * ea, int32 value, int32 comperand ) { return ( cellAtomicCompareAndSwap32( (uint32_t*)ea, comperand, value ) == ( uint32_t ) comperand ); }
  319. PLATFORM_INTERFACE inline int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand ) { return cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ); }
  320. PLATFORM_INTERFACE inline bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) { return ( cellAtomicCompareAndSwap64( ( uint64_t* ) pDest, comperand, value ) == ( uint64_t ) comperand ); }
  321. #elif defined( _X360 )
  322. #define TO_INTERLOCK_PARAM(p) ((volatile long *)p)
  323. #define TO_INTERLOCK_PTR_PARAM(p) ((void **)p)
  324. FORCEINLINE int32 ThreadInterlockedIncrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedIncrement( TO_INTERLOCK_PARAM(pDest) ); }
  325. FORCEINLINE int32 ThreadInterlockedDecrement( int32 volatile *pDest ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedDecrement( TO_INTERLOCK_PARAM(pDest) ); }
  326. FORCEINLINE int32 ThreadInterlockedExchange( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchange( TO_INTERLOCK_PARAM(pDest), value ); }
  327. FORCEINLINE int32 ThreadInterlockedExchangeAdd( int32 volatile *pDest, int32 value ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedExchangeAdd( TO_INTERLOCK_PARAM(pDest), value ); }
  328. FORCEINLINE int32 ThreadInterlockedCompareExchange( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ); }
  329. FORCEINLINE bool ThreadInterlockedAssignIf( int32 volatile *pDest, int32 value, int32 comperand ) { Assert( (size_t)pDest % 4 == 0 ); return ( InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ) == comperand ); }
  330. #else
  331. // non 32-bit windows and 360 implementation
  332. PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ) NOINLINE;
  333. PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE;
  334. PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE;
  335. PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ) NOINLINE;
  336. PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ) NOINLINE;
  337. PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE;
  338. #endif
  339. #if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( PLATFORM_64BITS )
  340. #define TIPTR()
  341. inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)( ( intp )ThreadInterlockedExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value) ) ); }
  342. inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) ); }
  343. inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) == reinterpret_cast<intp>(comperand) ); }
  344. #else
  345. PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE;
  346. PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE;
  347. PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE;
  348. #endif
  349. inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); }
  350. inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); }
  351. 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 ) ); }
  352. 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 ) ); }
  353. #ifndef _PS3
  354. PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE;
  355. PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE;
  356. #endif
  357. PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE;
  358. #ifdef COMPILER_MSVC32
  359. PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE;
  360. PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE;
  361. PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE;
  362. #elif defined(POSIX)
  363. inline int64 ThreadInterlockedIncrement64( int64 volatile *p )
  364. {
  365. AssertDbg( (size_t)p % 8 == 0 );
  366. return __sync_fetch_and_add( p, 1 ) + 1;
  367. }
  368. inline int64 ThreadInterlockedDecrement64( int64 volatile *p )
  369. {
  370. AssertDbg( (size_t)p % 8 == 0 );
  371. return __sync_fetch_and_add( p, -1 ) - 1;
  372. }
  373. #endif
  374. #ifdef COMPILER_MSVC64
  375. // 64 bit windows can use intrinsics for these, 32-bit can't
  376. #pragma intrinsic( _InterlockedCompareExchange64 )
  377. #pragma intrinsic( _InterlockedExchange64 )
  378. #pragma intrinsic( _InterlockedExchangeAdd64 )
  379. inline int64 ThreadInterlockedCompareExchange64( int64 volatile *p, int64 value, int64 comparand ) { AssertDbg( (size_t)p % 8 == 0 ); return _InterlockedCompareExchange64( (volatile int64*)p, value, comparand ); }
  380. inline int64 ThreadInterlockedExchangeAdd64( int64 volatile *p, int64 value ) { AssertDbg( (size_t)p % 8 == 0 ); return _InterlockedExchangeAdd64( (volatile int64*)p, value ); }
  381. #endif
  382. inline unsigned ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); }
  383. inline unsigned ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); }
  384. inline unsigned ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); }
  385. inline unsigned ThreadInterlockedExchange( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); }
  386. inline unsigned ThreadInterlockedExchangeAdd( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); }
  387. inline unsigned ThreadInterlockedCompareExchange( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); }
  388. inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32 comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); }
  389. //inline int ThreadInterlockedExchangeSubtract( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); }
  390. //inline int ThreadInterlockedIncrement( int volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); }
  391. //inline int ThreadInterlockedDecrement( int volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); }
  392. //inline int ThreadInterlockedExchange( int volatile *p, int value ) { return ThreadInterlockedExchange( (int32 volatile *)p, value ); }
  393. //inline int ThreadInterlockedExchangeAdd( int volatile *p, int value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); }
  394. //inline int ThreadInterlockedCompareExchange( int volatile *p, int value, int comperand ) { return ThreadInterlockedCompareExchange( (int32 volatile *)p, value, comperand ); }
  395. //inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); }
  396. #if defined( _WIN64 )
  397. typedef __m128i int128;
  398. inline int128 int128_zero() { return _mm_setzero_si128(); }
  399. PLATFORM_INTERFACE bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand ) NOINLINE;
  400. #endif
  401. //-----------------------------------------------------------------------------
  402. // Access to VTune thread profiling
  403. //-----------------------------------------------------------------------------
  404. #if defined(_WIN32) && defined(THREAD_PROFILER)
  405. PLATFORM_INTERFACE void ThreadNotifySyncPrepare(void *p);
  406. PLATFORM_INTERFACE void ThreadNotifySyncCancel(void *p);
  407. PLATFORM_INTERFACE void ThreadNotifySyncAcquired(void *p);
  408. PLATFORM_INTERFACE void ThreadNotifySyncReleasing(void *p);
  409. #else
  410. #define ThreadNotifySyncPrepare(p) ((void)0)
  411. #define ThreadNotifySyncCancel(p) ((void)0)
  412. #define ThreadNotifySyncAcquired(p) ((void)0)
  413. #define ThreadNotifySyncReleasing(p) ((void)0)
  414. #endif
  415. //-----------------------------------------------------------------------------
  416. // Encapsulation of a thread local datum (needed because THREAD_LOCAL doesn't
  417. // work in a DLL loaded with LoadLibrary()
  418. //-----------------------------------------------------------------------------
  419. #ifndef NO_THREAD_LOCAL
  420. #if ( defined(_LINUX) && defined(DEDICATED) ) && !defined(OSX)
  421. // linux totally supports compiler thread locals, even across dll's.
  422. #define PLAT_COMPILER_SUPPORTED_THREADLOCALS 1
  423. #define CTHREADLOCALINTEGER( typ ) __thread int
  424. #define CTHREADLOCALINT __thread int
  425. #define CTHREADLOCALPTR( typ ) __thread typ *
  426. #define CTHREADLOCAL( typ ) __thread typ
  427. #define GETLOCAL( x ) ( x )
  428. #ifndef TIER0_DLL_EXPORT
  429. DLL_IMPORT __thread int g_nThreadID;
  430. #endif
  431. #endif
  432. #if defined(WIN32) || defined(OSX) || defined( _PS3 ) || ( defined (_LINUX) && !defined(DEDICATED) )
  433. #ifndef __AFXTLS_H__ // not compatible with some Windows headers
  434. #if defined(_PS3)
  435. #define CTHREADLOCALINT CThreadLocalInt<int>
  436. #define CTHREADLOCALINTEGER( typ ) CThreadLocalInt<typ>
  437. #define CTHREADLOCALPTR( typ ) CThreadLocalPtr<typ>
  438. #define CTHREADLOCAL( typ ) CThreadLocal<typ>
  439. #define GETLOCAL( x ) ( x.Get() )
  440. #else
  441. #define CTHREADLOCALINT GenericThreadLocals::CThreadLocalInt<int>
  442. #define CTHREADLOCALINTEGER( typ ) GenericThreadLocals::CThreadLocalInt<typ>
  443. #define CTHREADLOCALPTR( typ ) GenericThreadLocals::CThreadLocalPtr<typ>
  444. #define CTHREADLOCAL( typ ) GenericThreadLocals::CThreadLocal<typ>
  445. #define GETLOCAL( x ) ( x.Get() )
  446. #endif
  447. #if !defined(_PS3)
  448. namespace GenericThreadLocals
  449. {
  450. #endif
  451. // a (not so efficient) implementation of thread locals for compilers without full support (i.e. visual c).
  452. // don't use this explicity - instead, use the CTHREADxxx macros above.
  453. class PLATFORM_CLASS CThreadLocalBase
  454. {
  455. public:
  456. CThreadLocalBase();
  457. ~CThreadLocalBase();
  458. void * Get() const;
  459. void Set(void *);
  460. private:
  461. #if defined(POSIX) && !defined( _GAMECONSOLE )
  462. pthread_key_t m_index;
  463. #else
  464. uint32 m_index;
  465. #endif
  466. };
  467. //---------------------------------------------------------
  468. template <class T>
  469. class CThreadLocal : public CThreadLocalBase
  470. {
  471. public:
  472. CThreadLocal()
  473. {
  474. #ifdef PLATFORM_64BITS
  475. COMPILE_TIME_ASSERT( sizeof(T) <= sizeof(void *) );
  476. #else
  477. COMPILE_TIME_ASSERT( sizeof(T) == sizeof(void *) );
  478. #endif
  479. }
  480. void operator=( T i ) { Set( i ); }
  481. T Get() const
  482. {
  483. #ifdef PLATFORM_64BITS
  484. void *pData = CThreadLocalBase::Get();
  485. return *reinterpret_cast<T*>( &pData );
  486. #else
  487. #ifdef COMPILER_MSVC
  488. #pragma warning ( disable : 4311 )
  489. #endif
  490. return reinterpret_cast<T>( CThreadLocalBase::Get() );
  491. #ifdef COMPILER_MSVC
  492. #pragma warning ( default : 4311 )
  493. #endif
  494. #endif
  495. }
  496. void Set(T val)
  497. {
  498. #ifdef PLATFORM_64BITS
  499. void* pData = 0;
  500. *reinterpret_cast<T*>( &pData ) = val;
  501. CThreadLocalBase::Set( pData );
  502. #else
  503. #ifdef COMPILER_MSVC
  504. #pragma warning ( disable : 4312 )
  505. #endif
  506. CThreadLocalBase::Set( reinterpret_cast<void *>(val) );
  507. #ifdef COMPILER_MSVC
  508. #pragma warning ( default : 4312 )
  509. #endif
  510. #endif
  511. }
  512. };
  513. //---------------------------------------------------------
  514. template <class T = int32>
  515. class CThreadLocalInt : public CThreadLocal<T>
  516. {
  517. public:
  518. operator const T() const { return this->Get(); }
  519. int operator=( T i ) { this->Set( i ); return i; }
  520. T operator++() { T i = this->Get(); this->Set( ++i ); return i; }
  521. T operator++(int) { T i = this->Get(); this->Set( i + 1 ); return i; }
  522. T operator--() { T i = this->Get(); this->Set( --i ); return i; }
  523. T operator--(int) { T i = this->Get(); this->Set( i - 1 ); return i; }
  524. inline CThreadLocalInt( ) { }
  525. inline CThreadLocalInt( const T &initialvalue )
  526. {
  527. this->Set( initialvalue );
  528. }
  529. };
  530. //---------------------------------------------------------
  531. template <class T>
  532. class CThreadLocalPtr : private CThreadLocalBase
  533. {
  534. public:
  535. CThreadLocalPtr() {}
  536. operator const void *() const { return (const T *)Get(); }
  537. operator void *() { return (T *)Get(); }
  538. operator const T *() const { return (const T *)Get(); }
  539. operator const T *() { return (const T *)Get(); }
  540. operator T *() { return (T *)Get(); }
  541. T * operator=( T *p ) { Set( p ); return p; }
  542. bool operator !() const { return (!Get()); }
  543. bool operator!=( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() != NULL); }
  544. bool operator==( int i ) const { AssertMsg( i == 0, "Only NULL allowed on integer compare" ); return (Get() == NULL); }
  545. bool operator==( const void *p ) const { return (Get() == p); }
  546. bool operator!=( const void *p ) const { return (Get() != p); }
  547. bool operator==( const T *p ) const { return operator==((const void*)p); }
  548. bool operator!=( const T *p ) const { return operator!=((const void*)p); }
  549. T * operator->() { return (T *)Get(); }
  550. T & operator *() { return *((T *)Get()); }
  551. const T * operator->() const { return (const T *)Get(); }
  552. const T & operator *() const { return *((const T *)Get()); }
  553. const T & operator[]( int i ) const { return *((const T *)Get() + i); }
  554. T & operator[]( int i ) { return *((T *)Get() + i); }
  555. private:
  556. // Disallowed operations
  557. CThreadLocalPtr( T *pFrom );
  558. CThreadLocalPtr( const CThreadLocalPtr<T> &from );
  559. T **operator &();
  560. T * const *operator &() const;
  561. void operator=( const CThreadLocalPtr<T> &from );
  562. bool operator==( const CThreadLocalPtr<T> &p ) const;
  563. bool operator!=( const CThreadLocalPtr<T> &p ) const;
  564. };
  565. #if !defined(_PS3)
  566. }
  567. #endif
  568. #ifdef _OSX
  569. PLATFORM_INTERFACE GenericThreadLocals::CThreadLocalInt<int> g_nThreadID;
  570. #else // _OSX
  571. #ifndef TIER0_DLL_EXPORT
  572. #ifndef _PS3
  573. DLL_GLOBAL_IMPORT CTHREADLOCALINT g_nThreadID;
  574. #endif // !_PS3
  575. #endif // TIER0_DLL_EXPORT
  576. #endif // _OSX
  577. #endif /// afx32
  578. #endif //__win32
  579. #endif // NO_THREAD_LOCAL
  580. #ifdef _WIN64
  581. // 64 bit windows can use intrinsics for these, 32-bit can't
  582. #pragma intrinsic( _InterlockedCompareExchange64 )
  583. #pragma intrinsic( _InterlockedExchange64 )
  584. #pragma intrinsic( _InterlockedExchangeAdd64 )
  585. inline int64 ThreadInterlockedIncrement64(int64 volatile *p) { AssertDbg((size_t)p % 8 == 0); return _InterlockedIncrement64((volatile int64*)p); }
  586. inline int64 ThreadInterlockedDecrement64(int64 volatile *p) { AssertDbg((size_t)p % 8 == 0); return _InterlockedDecrement64((volatile int64*)p); }
  587. #endif
  588. //-----------------------------------------------------------------------------
  589. //
  590. // A super-fast thread-safe integer A simple class encapsulating the notion of an
  591. // atomic integer used across threads that uses the built in and faster
  592. // "interlocked" functionality rather than a full-blown mutex. Useful for simple
  593. // things like reference counts, etc.
  594. //
  595. //-----------------------------------------------------------------------------
  596. template <typename T>
  597. class CInterlockedIntT
  598. {
  599. public:
  600. CInterlockedIntT() : m_value( 0 ) { COMPILE_TIME_ASSERT( ( sizeof(T) == sizeof(int32) ) || ( sizeof(T) == sizeof(int64) ) ); }
  601. CInterlockedIntT( T value ) : m_value( value ) {}
  602. T operator()( void ) const { return m_value; }
  603. operator T() const { return m_value; }
  604. bool operator!() const { return ( m_value == 0 ); }
  605. bool operator==( T rhs ) const { return ( m_value == rhs ); }
  606. bool operator!=( T rhs ) const { return ( m_value != rhs ); }
  607. T operator++() {
  608. if ( sizeof(T) == sizeof(int32) )
  609. return (T)ThreadInterlockedIncrement( (int32 *)&m_value );
  610. else
  611. return (T)ThreadInterlockedIncrement64( (int64 *)&m_value );
  612. }
  613. T operator++(int) { return operator++() - 1; }
  614. T operator--() {
  615. if ( sizeof(T) == sizeof(int32) )
  616. return (T)ThreadInterlockedDecrement( (int32 *)&m_value );
  617. else
  618. return (T)ThreadInterlockedDecrement64( (int64 *)&m_value );
  619. }
  620. T operator--(int) { return operator--() + 1; }
  621. bool AssignIf( T conditionValue, T newValue )
  622. {
  623. if ( sizeof(T) == sizeof(int32) )
  624. return ThreadInterlockedAssignIf( (int32 *)&m_value, (int32)newValue, (int32)conditionValue );
  625. else
  626. return ThreadInterlockedAssignIf64( (int64 *)&m_value, (int64)newValue, (int64)conditionValue );
  627. }
  628. T operator=( T newValue ) {
  629. if ( sizeof(T) == sizeof(int32) )
  630. ThreadInterlockedExchange((int32 *)&m_value, newValue);
  631. else
  632. ThreadInterlockedExchange64((int64 *)&m_value, newValue);
  633. return m_value;
  634. }
  635. // Atomic add is like += except it returns the previous value as its return value
  636. T AtomicAdd( T add ) {
  637. if ( sizeof(T) == sizeof(int32) )
  638. return (T)ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add );
  639. else
  640. return (T)ThreadInterlockedExchangeAdd64( (int64 *)&m_value, (int64)add );
  641. }
  642. void operator+=( T add ) {
  643. if ( sizeof(T) == sizeof(int32) )
  644. ThreadInterlockedExchangeAdd( (int32 *)&m_value, (int32)add );
  645. else
  646. ThreadInterlockedExchangeAdd64( (int64 *)&m_value, (int64)add );
  647. }
  648. void operator-=( T subtract ) { operator+=( -subtract ); }
  649. void operator*=( T multiplier ) {
  650. T original, result;
  651. do
  652. {
  653. original = m_value;
  654. result = original * multiplier;
  655. } while ( !AssignIf( original, result ) );
  656. }
  657. void operator/=( T divisor ) {
  658. T original, result;
  659. do
  660. {
  661. original = m_value;
  662. result = original / divisor;
  663. } while ( !AssignIf( original, result ) );
  664. }
  665. T operator+( T rhs ) const { return m_value + rhs; }
  666. T operator-( T rhs ) const { return m_value - rhs; }
  667. T InterlockedExchange(T newValue) {
  668. if (sizeof(T) == sizeof(int32))
  669. return (T)ThreadInterlockedExchange((int32*)&m_value, newValue);
  670. else
  671. return (T)ThreadInterlockedExchange64((int64*)&m_value, newValue);
  672. }
  673. private:
  674. volatile T m_value;
  675. };
  676. typedef CInterlockedIntT<int> CInterlockedInt;
  677. typedef CInterlockedIntT<unsigned> CInterlockedUInt;
  678. //-----------------------------------------------------------------------------
  679. #ifdef _M_X64
  680. template <typename T>
  681. class CInterlockedPtr
  682. {
  683. public:
  684. CInterlockedPtr() : m_value( 0 ) {}
  685. CInterlockedPtr( T *value ) : m_value( value ) {}
  686. operator T *() const { return m_value; }
  687. bool operator!() const { return ( m_value == 0 ); }
  688. bool operator==( T *rhs ) const { return ( m_value == rhs ); }
  689. bool operator!=( T *rhs ) const { return ( m_value != rhs ); }
  690. T *operator++() { return ((T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, sizeof(T) )) + 1; }
  691. T *operator++(int) { return (T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, sizeof(T) ); }
  692. T *operator--() { return ((T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, -sizeof(T) )) - 1; }
  693. T *operator--(int) { return (T *)_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, -sizeof(T) ); }
  694. bool AssignIf( T *conditionValue, T *newValue ) { return _InterlockedCompareExchangePointer( (void * volatile *)&m_value, newValue, conditionValue ) == conditionValue; }
  695. T *operator=( T *newValue ) { _InterlockedExchangePointer( (void * volatile *) &m_value, newValue ); return newValue; }
  696. void operator+=( int add ) { _InterlockedExchangeAdd64( (volatile __int64 *)&m_value, add * sizeof(T) ); }
  697. void operator-=( int subtract ) { operator+=( -subtract ); }
  698. // Atomic add is like += except it returns the previous value as its return value
  699. T *AtomicAdd( int add ) { return ( T * )_InterlockedExchangeAdd64( (volatile __int64 *)&m_value, add * sizeof(T) ); }
  700. T *operator+( int rhs ) const { return m_value + rhs; }
  701. T *operator-( int rhs ) const { return m_value - rhs; }
  702. T *operator+( unsigned rhs ) const { return m_value + rhs; }
  703. T *operator-( unsigned rhs ) const { return m_value - rhs; }
  704. size_t operator-( T *p ) const { return m_value - p; }
  705. size_t operator-( const CInterlockedPtr<T> &p ) const { return m_value - p.m_value; }
  706. private:
  707. T * volatile m_value;
  708. };
  709. #else
  710. template <typename T>
  711. class CInterlockedPtr
  712. {
  713. public:
  714. CInterlockedPtr() : m_value( 0 )
  715. {
  716. #ifdef PLATFORM_64BITS
  717. COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int64) );
  718. #define THREADINTERLOCKEDEXCHANGEADD( _dest, _value ) ThreadInterlockedExchangeAdd64( (int64 *)(_dest), _value )
  719. #else // PLATFORM_64BITS
  720. COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int32) );
  721. #define THREADINTERLOCKEDEXCHANGEADD( _dest, _value ) ThreadInterlockedExchangeAdd( (int32 *)_dest, _value )
  722. #endif // PLATFORM_64BITS
  723. }
  724. CInterlockedPtr( T *value ) : m_value( value ) {}
  725. operator T *() const { return m_value; }
  726. bool operator!() const { return ( m_value == 0 ); }
  727. bool operator==( T *rhs ) const { return ( m_value == rhs ); }
  728. bool operator!=( T *rhs ) const { return ( m_value != rhs ); }
  729. T *operator++() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, sizeof(T) )) + 1; }
  730. T *operator++(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, sizeof(T) ); }
  731. T *operator--() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, -sizeof(T) )) - 1; }
  732. T *operator--(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, -sizeof(T) ); }
  733. bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); }
  734. T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; }
  735. void operator+=( int add ) { THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, add * sizeof(T) ); }
  736. void operator-=( int subtract ) { operator+=( -subtract ); }
  737. // Atomic add is like += except it returns the previous value as its return value
  738. T *AtomicAdd( int add ) { return ( T * ) THREADINTERLOCKEDEXCHANGEADD( (int32 *)&m_value, add * sizeof(T) ); }
  739. T *operator+( int rhs ) const { return m_value + rhs; }
  740. T *operator-( int rhs ) const { return m_value - rhs; }
  741. T *operator+( unsigned rhs ) const { return m_value + rhs; }
  742. T *operator-( unsigned rhs ) const { return m_value - rhs; }
  743. size_t operator-( T *p ) const { return m_value - p; }
  744. size_t operator-( const CInterlockedPtr<T> &p ) const { return m_value - p.m_value; }
  745. private:
  746. T * volatile m_value;
  747. #undef THREADINTERLOCKEDEXCHANGEADD
  748. };
  749. #endif
  750. //-----------------------------------------------------------------------------
  751. //
  752. // Platform independent for critical sections management
  753. //
  754. //-----------------------------------------------------------------------------
  755. class PLATFORM_CLASS CThreadMutex
  756. {
  757. public:
  758. CThreadMutex();
  759. ~CThreadMutex();
  760. //------------------------------------------------------
  761. // Mutex acquisition/release. Const intentionally defeated.
  762. //------------------------------------------------------
  763. void Lock();
  764. void Lock() const { (const_cast<CThreadMutex *>(this))->Lock(); }
  765. void Unlock();
  766. void Unlock() const { (const_cast<CThreadMutex *>(this))->Unlock(); }
  767. bool TryLock();
  768. bool TryLock() const { return (const_cast<CThreadMutex *>(this))->TryLock(); }
  769. void LockSilent(); // A Lock() operation which never spews. Required by the logging system to prevent badness.
  770. void UnlockSilent(); // An Unlock() operation which never spews. Required by the logging system to prevent badness.
  771. //------------------------------------------------------
  772. // Use this to make deadlocks easier to track by asserting
  773. // when it is expected that the current thread owns the mutex
  774. //------------------------------------------------------
  775. bool AssertOwnedByCurrentThread();
  776. //------------------------------------------------------
  777. // On windows with THREAD_MUTEX_TRACING_ENABLED defined, this returns
  778. // true if the mutex is owned by the current thread.
  779. //------------------------------------------------------
  780. bool IsOwnedByCurrentThread_DebugOnly();
  781. //------------------------------------------------------
  782. // Enable tracing to track deadlock problems
  783. //------------------------------------------------------
  784. void SetTrace( bool );
  785. private:
  786. // Disallow copying
  787. CThreadMutex( const CThreadMutex & );
  788. CThreadMutex &operator=( const CThreadMutex & );
  789. #if defined( _WIN32 )
  790. // Efficient solution to breaking the windows.h dependency, invariant is tested.
  791. #ifdef _WIN64
  792. #define TT_SIZEOF_CRITICALSECTION 40
  793. #else
  794. #ifndef _X360
  795. #define TT_SIZEOF_CRITICALSECTION 24
  796. #else
  797. #define TT_SIZEOF_CRITICALSECTION 28
  798. #endif // !_X360
  799. #endif // _WIN64
  800. byte m_CriticalSection[TT_SIZEOF_CRITICALSECTION];
  801. #elif defined( _PS3 )
  802. sys_mutex_t m_Mutex;
  803. #elif defined(POSIX)
  804. pthread_mutex_t m_Mutex;
  805. pthread_mutexattr_t m_Attr;
  806. #else
  807. #error
  808. #endif
  809. #ifdef THREAD_MUTEX_TRACING_SUPPORTED
  810. // Debugging (always herge to allow mixed debug/release builds w/o changing size)
  811. uint m_currentOwnerID;
  812. uint16 m_lockCount;
  813. bool m_bTrace;
  814. #endif
  815. };
  816. //-----------------------------------------------------------------------------
  817. //
  818. // An alternative mutex that is useful for cases when thread contention is
  819. // rare, but a mutex is required. Instances should be declared volatile.
  820. // Sleep of 0 may not be sufficient to keep high priority threads from starving
  821. // lesser threads. This class is not a suitable replacement for a critical
  822. // section if the resource contention is high.
  823. //
  824. //-----------------------------------------------------------------------------
  825. #if !defined(THREAD_PROFILER)
  826. class CThreadFastMutex
  827. {
  828. public:
  829. CThreadFastMutex()
  830. : m_ownerID( 0 ),
  831. m_depth( 0 )
  832. {
  833. }
  834. private:
  835. FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile
  836. {
  837. if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile int32 *)&m_ownerID, (int32)threadId, 0 ) )
  838. return false;
  839. ThreadMemoryBarrier();
  840. ++m_depth;
  841. return true;
  842. }
  843. bool TryLock( const uint32 threadId ) volatile
  844. {
  845. return TryLockInline( threadId );
  846. }
  847. PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile;
  848. public:
  849. bool TryLock() volatile
  850. {
  851. #ifdef _DEBUG
  852. if ( m_depth == INT_MAX )
  853. DebuggerBreak();
  854. if ( m_depth < 0 )
  855. DebuggerBreak();
  856. #endif
  857. return TryLockInline( ThreadGetCurrentId() );
  858. }
  859. #ifndef _DEBUG
  860. FORCEINLINE
  861. #endif
  862. void Lock( unsigned int nSpinSleepTime = 0 ) volatile
  863. {
  864. const uint32 threadId = ThreadGetCurrentId();
  865. if ( !TryLockInline( threadId ) )
  866. {
  867. ThreadPause();
  868. Lock( threadId, nSpinSleepTime );
  869. }
  870. #ifdef _DEBUG
  871. if ( m_ownerID != (int32)ThreadGetCurrentId() )
  872. DebuggerBreak();
  873. if ( m_depth == INT_MAX )
  874. DebuggerBreak();
  875. if ( m_depth < 0 )
  876. DebuggerBreak();
  877. #endif
  878. }
  879. #ifndef _DEBUG
  880. FORCEINLINE
  881. #endif
  882. void Unlock() volatile
  883. {
  884. #ifdef _DEBUG
  885. if ( m_ownerID != (int32)ThreadGetCurrentId() )
  886. DebuggerBreak();
  887. if ( m_depth <= 0 )
  888. DebuggerBreak();
  889. #endif
  890. --m_depth;
  891. if ( !m_depth )
  892. {
  893. ThreadMemoryBarrier();
  894. ThreadInterlockedExchange( &m_ownerID, 0 );
  895. }
  896. }
  897. bool TryLock() const volatile { return (const_cast<CThreadFastMutex *>(this))->TryLock(); }
  898. void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadFastMutex *>(this))->Lock( nSpinSleepTime ); }
  899. void Unlock() const volatile { (const_cast<CThreadFastMutex *>(this))->Unlock(); }
  900. // To match regular CThreadMutex:
  901. bool AssertOwnedByCurrentThread() { return true; }
  902. void SetTrace( bool ) {}
  903. uint32 GetOwnerId() const { return m_ownerID; }
  904. int GetDepth() const { return m_depth; }
  905. private:
  906. volatile uint32 m_ownerID;
  907. int m_depth;
  908. };
  909. class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex
  910. {
  911. public:
  912. CAlignedThreadFastMutex()
  913. {
  914. Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 );
  915. }
  916. private:
  917. uint8 pad[128-sizeof(CThreadFastMutex)];
  918. };
  919. #else
  920. #ifdef _PS3
  921. class CThreadFastMutex
  922. {
  923. public:
  924. CThreadFastMutex();
  925. ~CThreadFastMutex();
  926. //------------------------------------------------------
  927. // Mutex acquisition/release. Const intentionally defeated.
  928. //------------------------------------------------------
  929. void Lock();
  930. void Lock() const { (const_cast<CThreadFastMutex *>(this))->Lock(); }
  931. void Unlock();
  932. void Unlock() const { (const_cast<CThreadFastMutex *>(this))->Unlock(); }
  933. bool TryLock();
  934. bool TryLock() const { return (const_cast<CThreadFastMutex *>(this))->TryLock(); }
  935. //------------------------------------------------------
  936. // Use this to make deadlocks easier to track by asserting
  937. // when it is expected that the current thread owns the mutex
  938. //------------------------------------------------------
  939. bool AssertOwnedByCurrentThread();
  940. //------------------------------------------------------
  941. // Enable tracing to track deadlock problems
  942. //------------------------------------------------------
  943. void SetTrace( bool );
  944. private:
  945. // Disallow copying
  946. CThreadFastMutex( const CThreadFastMutex & );
  947. //CThreadFastMutex &operator=( const CThreadFastMutex & );
  948. sys_lwmutex_t m_Mutex;
  949. sys_mutex_t m_SlowMutex;
  950. };
  951. #else
  952. typedef CThreadMutex CThreadFastMutex;
  953. #endif
  954. class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex
  955. {
  956. public:
  957. CAlignedThreadFastMutex()
  958. {
  959. Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 );
  960. }
  961. private:
  962. uint8 pad[128-sizeof(CThreadFastMutex)];
  963. };
  964. #endif
  965. //-----------------------------------------------------------------------------
  966. //
  967. //-----------------------------------------------------------------------------
  968. class CThreadNullMutex
  969. {
  970. public:
  971. static void Lock() {}
  972. static void Unlock() {}
  973. static bool TryLock() { return true; }
  974. static bool AssertOwnedByCurrentThread() { return true; }
  975. static void SetTrace( bool b ) {}
  976. static uint32 GetOwnerId() { return 0; }
  977. static int GetDepth() { return 0; }
  978. };
  979. //-----------------------------------------------------------------------------
  980. //
  981. // A mutex decorator class used to control the use of a mutex, to make it
  982. // less expensive when not multithreading
  983. //
  984. //-----------------------------------------------------------------------------
  985. template <class BaseClass, bool *pCondition>
  986. class CThreadConditionalMutex : public BaseClass
  987. {
  988. public:
  989. void Lock() { if ( *pCondition ) BaseClass::Lock(); }
  990. void Lock() const { if ( *pCondition ) BaseClass::Lock(); }
  991. void Unlock() { if ( *pCondition ) BaseClass::Unlock(); }
  992. void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); }
  993. bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; }
  994. bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; }
  995. bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; }
  996. void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); }
  997. };
  998. //-----------------------------------------------------------------------------
  999. // Mutex decorator that blows up if another thread enters
  1000. //-----------------------------------------------------------------------------
  1001. template <class BaseClass>
  1002. class CThreadTerminalMutex : public BaseClass
  1003. {
  1004. public:
  1005. bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
  1006. bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
  1007. void Lock() { if ( !TryLock() ) BaseClass::Lock(); }
  1008. void Lock() const { if ( !TryLock() ) BaseClass::Lock(); }
  1009. };
  1010. //-----------------------------------------------------------------------------
  1011. //
  1012. // Class to Lock a critical section, and unlock it automatically
  1013. // when the lock goes out of scope
  1014. //
  1015. //-----------------------------------------------------------------------------
  1016. template <class MUTEX_TYPE = CThreadMutex>
  1017. class CAutoLockT
  1018. {
  1019. public:
  1020. FORCEINLINE CAutoLockT( MUTEX_TYPE &lock)
  1021. : m_lock(lock)
  1022. {
  1023. m_lock.Lock();
  1024. }
  1025. FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock)
  1026. : m_lock(const_cast<MUTEX_TYPE &>(lock))
  1027. {
  1028. m_lock.Lock();
  1029. }
  1030. FORCEINLINE ~CAutoLockT()
  1031. {
  1032. m_lock.Unlock();
  1033. }
  1034. private:
  1035. MUTEX_TYPE &m_lock;
  1036. // Disallow copying
  1037. CAutoLockT<MUTEX_TYPE>( const CAutoLockT<MUTEX_TYPE> & );
  1038. CAutoLockT<MUTEX_TYPE> &operator=( const CAutoLockT<MUTEX_TYPE> & );
  1039. };
  1040. typedef CAutoLockT<CThreadMutex> CAutoLock;
  1041. //---------------------------------------------------------
  1042. template <int size> struct CAutoLockTypeDeducer {};
  1043. template <> struct CAutoLockTypeDeducer<sizeof(CThreadMutex)> { typedef CThreadMutex Type_t; };
  1044. template <> struct CAutoLockTypeDeducer<sizeof(CThreadNullMutex)> { typedef CThreadNullMutex Type_t; };
  1045. #if !defined(THREAD_PROFILER)
  1046. template <> struct CAutoLockTypeDeducer<sizeof(CThreadFastMutex)> { typedef CThreadFastMutex Type_t; };
  1047. template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; };
  1048. #else
  1049. template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; };
  1050. #endif
  1051. #define AUTO_LOCK_( type, mutex ) \
  1052. CAutoLockT< type > UNIQUE_ID( static_cast<const type &>( mutex ) )
  1053. #if defined(GNUC)
  1054. template<typename T> T strip_cv_quals_for_mutex(T&);
  1055. template<typename T> T strip_cv_quals_for_mutex(const T&);
  1056. template<typename T> T strip_cv_quals_for_mutex(volatile T&);
  1057. template<typename T> T strip_cv_quals_for_mutex(const volatile T&);
  1058. #define AUTO_LOCK( mutex ) \
  1059. AUTO_LOCK_( decltype(::strip_cv_quals_for_mutex(mutex)), mutex )
  1060. #elif defined( __clang__ )
  1061. #define AUTO_LOCK( mutex ) \
  1062. AUTO_LOCK_( typename CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex )
  1063. #else
  1064. #define AUTO_LOCK( mutex ) \
  1065. AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex )
  1066. #endif
  1067. #define AUTO_LOCK_FM( mutex ) \
  1068. AUTO_LOCK_( CThreadFastMutex, mutex )
  1069. #define LOCAL_THREAD_LOCK_( tag ) \
  1070. ; \
  1071. static CThreadFastMutex autoMutex_##tag; \
  1072. AUTO_LOCK( autoMutex_##tag )
  1073. #define LOCAL_THREAD_LOCK() \
  1074. LOCAL_THREAD_LOCK_(_)
  1075. //-----------------------------------------------------------------------------
  1076. //
  1077. // Base class for event, semaphore and mutex objects.
  1078. //
  1079. //-----------------------------------------------------------------------------
  1080. // TW_TIMEOUT must match WAIT_TIMEOUT definition
  1081. #define TW_TIMEOUT 0x00000102
  1082. // TW_FAILED must match WAIT_FAILED definition
  1083. #define TW_FAILED 0xFFFFFFFF
  1084. class PLATFORM_CLASS CThreadSyncObject
  1085. {
  1086. public:
  1087. ~CThreadSyncObject();
  1088. //-----------------------------------------------------
  1089. // Query if object is useful
  1090. //-----------------------------------------------------
  1091. bool operator!() const;
  1092. //-----------------------------------------------------
  1093. // Access handle
  1094. //-----------------------------------------------------
  1095. #ifdef _WIN32
  1096. operator HANDLE() { return GetHandle(); }
  1097. const HANDLE GetHandle() const { return m_hSyncObject; }
  1098. #endif
  1099. //-----------------------------------------------------
  1100. // Wait for a signal from the object
  1101. //-----------------------------------------------------
  1102. bool Wait( uint32 dwTimeout = TT_INFINITE );
  1103. //-----------------------------------------------------
  1104. // Wait for a signal from any of the specified objects.
  1105. //
  1106. // Returns the index of the object that signaled the event
  1107. // or THREADSYNC_TIMEOUT if the timeout was hit before the wait condition was met.
  1108. //
  1109. // Returns TW_FAILED if an incoming object is invalid.
  1110. //
  1111. // If bWaitAll=true, then it'll return 0 if all the objects were set.
  1112. //-----------------------------------------------------
  1113. static uint32 WaitForMultiple( int nObjects, CThreadSyncObject **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE );
  1114. // This builds a list of pointers and calls straight through to the other WaitForMultiple.
  1115. static uint32 WaitForMultiple( int nObjects, CThreadSyncObject *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE );
  1116. protected:
  1117. CThreadSyncObject();
  1118. void AssertUseable();
  1119. #ifdef _WIN32
  1120. HANDLE m_hSyncObject;
  1121. bool m_bCreatedHandle;
  1122. #elif defined( _PS3 )
  1123. static sys_lwmutex_t m_staticMutex;
  1124. static uint32_t m_bstaticMutexInitialized;
  1125. static uint32_t m_bstaticMutexInitializing;
  1126. #elif defined(POSIX)
  1127. pthread_mutex_t m_Mutex;
  1128. pthread_cond_t m_Condition;
  1129. bool m_bInitalized;
  1130. int m_cSet;
  1131. bool m_bManualReset;
  1132. bool m_bWakeForEvent;
  1133. #else
  1134. #error "Implement me"
  1135. #endif
  1136. private:
  1137. CThreadSyncObject( const CThreadSyncObject & );
  1138. CThreadSyncObject &operator=( const CThreadSyncObject & );
  1139. };
  1140. //-----------------------------------------------------------------------------
  1141. //
  1142. // Wrapper for unnamed event objects
  1143. //
  1144. //-----------------------------------------------------------------------------
  1145. //-----------------------------------------------------------------------------
  1146. //
  1147. // CThreadSemaphore
  1148. //
  1149. //-----------------------------------------------------------------------------
  1150. class PLATFORM_CLASS CThreadSemaphore : public CThreadSyncObject
  1151. {
  1152. public:
  1153. CThreadSemaphore(int32 initialValue, int32 maxValue);
  1154. //-----------------------------------------------------
  1155. // Increases the count of the semaphore object by a specified
  1156. // amount. Wait() decreases the count by one on return.
  1157. //-----------------------------------------------------
  1158. bool Release(int32 releaseCount = 1, int32 * pPreviousCount = NULL );
  1159. bool Wait( uint32 dwTimeout = TT_INFINITE );
  1160. private:
  1161. CThreadSemaphore(const CThreadSemaphore &);
  1162. CThreadSemaphore &operator=(const CThreadSemaphore &);
  1163. #ifdef _PS3
  1164. bool AddWaitingThread();
  1165. void RemoveWaitingThread();
  1166. sys_semaphore_t m_Semaphore;
  1167. sys_semaphore_value_t m_sema_max_val;
  1168. uint32_t m_numWaitingThread;
  1169. uint32_t m_bInitalized;
  1170. uint32_t m_semaCount;
  1171. #endif
  1172. };
  1173. #if defined( _WIN32 )
  1174. //-----------------------------------------------------------------------------
  1175. //
  1176. // A mutex suitable for out-of-process, multi-processor usage
  1177. //
  1178. //-----------------------------------------------------------------------------
  1179. class PLATFORM_CLASS CThreadFullMutex : public CThreadSyncObject
  1180. {
  1181. public:
  1182. CThreadFullMutex( bool bEstablishInitialOwnership = false, const char * pszName = NULL );
  1183. //-----------------------------------------------------
  1184. // Release ownership of the mutex
  1185. //-----------------------------------------------------
  1186. bool Release();
  1187. // To match regular CThreadMutex:
  1188. void Lock() { Wait(); }
  1189. void Lock( unsigned timeout ) { Wait( timeout ); }
  1190. void Unlock() { Release(); }
  1191. bool AssertOwnedByCurrentThread() { return true; }
  1192. void SetTrace( bool ) {}
  1193. private:
  1194. CThreadFullMutex( const CThreadFullMutex & );
  1195. CThreadFullMutex &operator=( const CThreadFullMutex & );
  1196. };
  1197. #endif
  1198. enum NamedEventResult_t
  1199. {
  1200. TT_EventDoesntExist = 0,
  1201. TT_EventNotSignaled,
  1202. TT_EventSignaled
  1203. };
  1204. #if defined( _PS3 )
  1205. //---------------------------------------------------------------------------
  1206. // CThreadEventWaitObject - the purpose of this class is to help implement
  1207. // WaitForMultipleObejcts on PS3.
  1208. //
  1209. // Each event maintains a linked list of CThreadEventWaitObjects. When a
  1210. // thread wants to wait on an event it passes the event a semaphore that
  1211. // ptr to see the index of the event that triggered it
  1212. //
  1213. // The thread-specific mutex is to ensure that setting the index and setting the
  1214. // semaphore are atomic
  1215. //---------------------------------------------------------------------------
  1216. class CThreadEventWaitObject
  1217. {
  1218. public:
  1219. CThreadEventWaitObject *m_pPrev, *m_pNext;
  1220. sys_semaphore_t *m_pSemaphore;
  1221. int m_index;
  1222. int *m_pFlag;
  1223. CThreadEventWaitObject() {}
  1224. void Init(sys_semaphore_t *pSem, int index, int *pFlag)
  1225. {
  1226. m_pSemaphore = pSem;
  1227. m_index = index;
  1228. m_pFlag = pFlag;
  1229. }
  1230. void Set();
  1231. };
  1232. #endif //_PS3
  1233. class PLATFORM_CLASS CThreadEvent : public CThreadSyncObject
  1234. {
  1235. public:
  1236. CThreadEvent( bool fManualReset = false );
  1237. #ifdef PLATFORM_WINDOWS
  1238. CThreadEvent( const char *name, bool initialState = false, bool bManualReset = false );
  1239. static NamedEventResult_t CheckNamedEvent( const char *name, uint32 dwTimeout = 0 );
  1240. CThreadEvent( HANDLE hHandle );
  1241. #endif
  1242. //-----------------------------------------------------
  1243. // Set the state to signaled
  1244. //-----------------------------------------------------
  1245. bool Set();
  1246. //-----------------------------------------------------
  1247. // Set the state to nonsignaled
  1248. //-----------------------------------------------------
  1249. bool Reset();
  1250. //-----------------------------------------------------
  1251. // Check if the event is signaled
  1252. //-----------------------------------------------------
  1253. bool Check(); // Please, use for debugging only!
  1254. bool Wait( uint32 dwTimeout = TT_INFINITE );
  1255. // See CThreadSyncObject for definitions of these functions.
  1256. static uint32 WaitForMultiple( int nObjects, CThreadEvent **ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE );
  1257. // To implement these, I need to check that casts are safe
  1258. static uint32 WaitForMultiple( int nObjects, CThreadEvent *ppObjects, bool bWaitAll, uint32 dwTimeout = TT_INFINITE );
  1259. #ifdef _PS3
  1260. void RegisterWaitingThread(sys_semaphore_t *pSemaphore, int index, int *flag);
  1261. void UnregisterWaitingThread(sys_semaphore_t *pSemaphore);
  1262. #endif
  1263. protected:
  1264. #ifdef _PS3
  1265. // These virtual functions need to be inline in order for the class to be exported from tier0.prx
  1266. virtual bool AddWaitingThread()
  1267. {
  1268. //This checks if the event is already signaled and if not creates a semaphore which will be signaled
  1269. //when the event is finally signaled.
  1270. bool result;
  1271. sys_lwmutex_lock(&m_staticMutex, 0);
  1272. if (m_bSet)
  1273. result=false;
  1274. else
  1275. {
  1276. result=true;
  1277. m_numWaitingThread++;
  1278. if ( m_numWaitingThread == 1 )
  1279. {
  1280. sys_semaphore_attribute_t semAttr;
  1281. sys_semaphore_attribute_initialize( semAttr );
  1282. int err = sys_semaphore_create( &m_Semaphore, &semAttr, 0, 256 );
  1283. Assert( err == CELL_OK );
  1284. m_bInitalized = true;
  1285. }
  1286. }
  1287. sys_lwmutex_unlock(&m_staticMutex);
  1288. return result;
  1289. }
  1290. virtual void RemoveWaitingThread()
  1291. {
  1292. sys_lwmutex_lock(&m_staticMutex, 0);
  1293. m_numWaitingThread--;
  1294. if ( m_numWaitingThread == 0)
  1295. {
  1296. int err = sys_semaphore_destroy( m_Semaphore );
  1297. Assert( err == CELL_OK );
  1298. m_bInitalized = false;
  1299. }
  1300. sys_lwmutex_unlock(&m_staticMutex);
  1301. }
  1302. #endif
  1303. private:
  1304. CThreadEvent( const CThreadEvent & );
  1305. CThreadEvent &operator=( const CThreadEvent & );
  1306. #if defined( _PS3 )
  1307. uint32_t m_bSet;
  1308. bool m_bManualReset;
  1309. sys_semaphore_t m_Semaphore;
  1310. uint32_t m_numWaitingThread;
  1311. uint32_t m_bInitalized;
  1312. CThreadEventWaitObject m_waitObjects[CTHREADEVENT_MAX_WAITING_THREADS+2];
  1313. CThreadEventWaitObject *m_pWaitObjectsPool;
  1314. CThreadEventWaitObject *m_pWaitObjectsList;
  1315. CThreadEventWaitObject* LLUnlinkNode(CThreadEventWaitObject *node);
  1316. CThreadEventWaitObject* LLLinkNode(CThreadEventWaitObject* list, CThreadEventWaitObject *node);
  1317. #endif
  1318. };
  1319. // Hard-wired manual event for use in array declarations
  1320. class CThreadManualEvent : public CThreadEvent
  1321. {
  1322. public:
  1323. CThreadManualEvent()
  1324. : CThreadEvent( true )
  1325. {
  1326. }
  1327. };
  1328. PLATFORM_INTERFACE int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll = true, unsigned timeout = TT_INFINITE );
  1329. inline int ThreadWaitForEvents( int nEvents, const CThreadEvent *pEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) { return ThreadWaitForObjects( nEvents, (const HANDLE *)pEvents, bWaitAll, timeout ); }
  1330. //-----------------------------------------------------------------------------
  1331. //
  1332. // CThreadRWLock
  1333. //
  1334. //-----------------------------------------------------------------------------
  1335. class PLATFORM_CLASS CThreadRWLock
  1336. {
  1337. public:
  1338. CThreadRWLock();
  1339. void LockForRead();
  1340. void UnlockRead();
  1341. void LockForWrite();
  1342. void UnlockWrite();
  1343. void LockForRead() const { const_cast<CThreadRWLock *>(this)->LockForRead(); }
  1344. void UnlockRead() const { const_cast<CThreadRWLock *>(this)->UnlockRead(); }
  1345. void LockForWrite() const { const_cast<CThreadRWLock *>(this)->LockForWrite(); }
  1346. void UnlockWrite() const { const_cast<CThreadRWLock *>(this)->UnlockWrite(); }
  1347. private:
  1348. void WaitForRead();
  1349. #ifdef WIN32
  1350. CThreadFastMutex m_mutex;
  1351. #else
  1352. CThreadMutex m_mutex;
  1353. #endif
  1354. CThreadEvent m_CanWrite;
  1355. CThreadEvent m_CanRead;
  1356. int m_nWriters;
  1357. int m_nActiveReaders;
  1358. int m_nPendingReaders;
  1359. };
  1360. //-----------------------------------------------------------------------------
  1361. //
  1362. // CThreadSpinRWLock
  1363. //
  1364. //-----------------------------------------------------------------------------
  1365. #ifndef OLD_SPINRWLOCK
  1366. class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock
  1367. {
  1368. public:
  1369. CThreadSpinRWLock()
  1370. {
  1371. m_lockInfo.m_i32 = 0;
  1372. m_writerId = 0;
  1373. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  1374. m_iWriteDepth = 0;
  1375. #endif
  1376. }
  1377. bool IsLockedForWrite();
  1378. bool IsLockedForRead();
  1379. FORCEINLINE bool TryLockForWrite();
  1380. bool TryLockForWrite_UnforcedInline();
  1381. void LockForWrite();
  1382. void SpinLockForWrite();
  1383. FORCEINLINE bool TryLockForRead();
  1384. bool TryLockForRead_UnforcedInline();
  1385. void LockForRead();
  1386. void SpinLockForRead();
  1387. void UnlockWrite();
  1388. void UnlockRead();
  1389. bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); }
  1390. bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); }
  1391. void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); }
  1392. void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); }
  1393. void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); }
  1394. void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); }
  1395. private:
  1396. enum
  1397. {
  1398. THREAD_SPIN = (8*1024)
  1399. };
  1400. union LockInfo_t
  1401. {
  1402. struct
  1403. {
  1404. #if PLAT_LITTLE_ENDIAN
  1405. uint16 m_nReaders;
  1406. uint16 m_fWriting;
  1407. #else
  1408. uint16 m_fWriting;
  1409. uint16 m_nReaders;
  1410. #endif
  1411. };
  1412. uint32 m_i32;
  1413. };
  1414. LockInfo_t m_lockInfo;
  1415. ThreadId_t m_writerId;
  1416. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  1417. int m_iWriteDepth;
  1418. uint32 pad;
  1419. #endif
  1420. } ALIGN8_POST;
  1421. #else
  1422. /* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles)
  1423. class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock
  1424. {
  1425. public:
  1426. CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( this, 0, sizeof( *this ) ); }
  1427. bool TryLockForWrite();
  1428. bool TryLockForRead();
  1429. void LockForRead();
  1430. void UnlockRead();
  1431. void LockForWrite();
  1432. void UnlockWrite();
  1433. bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); }
  1434. bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); }
  1435. void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); }
  1436. void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); }
  1437. void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); }
  1438. void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); }
  1439. private:
  1440. // This structure is used as an atomic & exchangeable 64-bit value. It would probably be better to just have one 64-bit value
  1441. // and accessor functions that make/break it, but at this late stage of development, I'm just wrapping it into union
  1442. // Beware of endianness: on Xbox/PowerPC m_writerId is high-word of m_i64; on PC, it's low-dword of m_i64
  1443. union LockInfo_t
  1444. {
  1445. struct
  1446. {
  1447. uint32 m_writerId;
  1448. int m_nReaders;
  1449. };
  1450. int64 m_i64;
  1451. };
  1452. bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand );
  1453. bool TryLockForWrite( const uint32 threadId );
  1454. void SpinLockForWrite( const uint32 threadId );
  1455. volatile LockInfo_t m_lockInfo;
  1456. CInterlockedInt m_nWriters;
  1457. } ALIGN8_POST;
  1458. */
  1459. #endif
  1460. //-----------------------------------------------------------------------------
  1461. //
  1462. // A thread wrapper similar to a Java thread.
  1463. //
  1464. //-----------------------------------------------------------------------------
  1465. #ifdef _PS3
  1466. // Everything must be inline for this to work across PRX boundaries
  1467. class CThread;
  1468. PLATFORM_INTERFACE CThread *GetCurThreadPS3();
  1469. PLATFORM_INTERFACE void SetCurThreadPS3( CThread * );
  1470. PLATFORM_INTERFACE void AllocateThreadID( void );
  1471. PLATFORM_INTERFACE void FreeThreadID( void );
  1472. #endif
  1473. class PLATFORM_CLASS CThread
  1474. {
  1475. public:
  1476. CThread();
  1477. virtual ~CThread();
  1478. //-----------------------------------------------------
  1479. const char *GetName();
  1480. void SetName( const char *pszName );
  1481. size_t CalcStackDepth( void *pStackVariable ) { return ((byte *)m_pStackBase - (byte *)pStackVariable); }
  1482. //-----------------------------------------------------
  1483. // Functions for the other threads
  1484. //-----------------------------------------------------
  1485. // Start thread running - error if already running
  1486. virtual bool Start( unsigned nBytesStack = 0, ThreadPriorityEnum_t nPriority = TP_PRIORITY_DEFAULT );
  1487. // Returns true if thread has been created and hasn't yet exited
  1488. bool IsAlive();
  1489. // This method causes the current thread to wait until this thread
  1490. // is no longer alive.
  1491. bool Join( unsigned timeout = TT_INFINITE );
  1492. // Access the thread handle directly
  1493. ThreadHandle_t GetThreadHandle();
  1494. #ifdef _WIN32
  1495. uint GetThreadId();
  1496. #endif
  1497. //-----------------------------------------------------
  1498. int GetResult();
  1499. //-----------------------------------------------------
  1500. // Functions for both this, and maybe, and other threads
  1501. //-----------------------------------------------------
  1502. // Forcibly, abnormally, but relatively cleanly stop the thread
  1503. void Stop( int exitCode = 0 );
  1504. // Get the priority
  1505. int GetPriority() const;
  1506. // Set the priority
  1507. bool SetPriority( int priority );
  1508. // Suspend a thread, can only call from the thread itself
  1509. unsigned Suspend();
  1510. // Resume a suspended thread
  1511. unsigned Resume();
  1512. // Check if thread is suspended
  1513. bool IsSuspended() { return !m_NotSuspendedEvent.Check(); }
  1514. // Force hard-termination of thread. Used for critical failures.
  1515. bool Terminate( int exitCode = 0 );
  1516. //-----------------------------------------------------
  1517. // Global methods
  1518. //-----------------------------------------------------
  1519. // Get the Thread object that represents the current thread, if any.
  1520. // Can return NULL if the current thread was not created using
  1521. // CThread
  1522. static CThread *GetCurrentCThread();
  1523. // Offer a context switch. Under Win32, equivalent to Sleep(0)
  1524. #ifdef Yield
  1525. #undef Yield
  1526. #endif
  1527. static void Yield();
  1528. // This method causes the current thread to yield and not to be
  1529. // scheduled for further execution until a certain amount of real
  1530. // time has elapsed, more or less. Duration is in milliseconds
  1531. static void Sleep( unsigned duration );
  1532. protected:
  1533. // Optional pre-run call, with ability to fail-create. Note Init()
  1534. // is forced synchronous with Start()
  1535. virtual bool Init();
  1536. // Thread will run this function on startup, must be supplied by
  1537. // derived class, performs the intended action of the thread.
  1538. virtual int Run() = 0;
  1539. // Called when the thread exits
  1540. virtual void OnExit();
  1541. // Allow for custom start waiting
  1542. virtual bool WaitForCreateComplete( CThreadEvent *pEvent );
  1543. const ThreadId_t GetThreadID() const { return (ThreadId_t)m_threadId; }
  1544. #ifdef PLATFORM_WINDOWS
  1545. const ThreadHandle_t GetThreadHandle() const { return (ThreadHandle_t)m_hThread; }
  1546. static unsigned long __stdcall ThreadProc( void * pv );
  1547. typedef unsigned long (__stdcall *ThreadProc_t)( void * );
  1548. #else
  1549. static void* ThreadProc( void * pv );
  1550. typedef void* (*ThreadProc_t)( void * pv );
  1551. #endif
  1552. static void ThreadProcRunWithMinidumpHandler( void *pv );
  1553. virtual ThreadProc_t GetThreadProc();
  1554. virtual bool IsThreadRunning();
  1555. CThreadMutex m_Lock;
  1556. CThreadEvent m_ExitEvent; // Set right before the thread's function exits.
  1557. private:
  1558. enum Flags
  1559. {
  1560. SUPPORT_STOP_PROTOCOL = 1 << 0
  1561. };
  1562. // Thread initially runs this. param is actually 'this'. function
  1563. // just gets this and calls ThreadProc
  1564. struct ThreadInit_t
  1565. {
  1566. CThread * pThread;
  1567. CThreadEvent *pInitCompleteEvent;
  1568. bool * pfInitSuccess;
  1569. #if defined( THREAD_PARENT_STACK_TRACE_ENABLED )
  1570. void * ParentStackTrace[THREAD_PARENT_STACK_TRACE_LENGTH];
  1571. #endif
  1572. };
  1573. // make copy constructor and assignment operator inaccessible
  1574. CThread( const CThread & );
  1575. CThread &operator=( const CThread & );
  1576. #ifdef _WIN32
  1577. HANDLE m_hThread;
  1578. ThreadId_t m_threadId;
  1579. #elif defined( _PS3 )
  1580. sys_ppu_thread_t m_threadId;
  1581. volatile sys_ppu_thread_t m_threadZombieId;
  1582. // Mutex and condition variable used by the Suspend / Resume logic
  1583. sys_mutex_t m_mutexSuspend;
  1584. sys_cond_t m_condSuspend;
  1585. //EAPS3 Event to indicate that a thread has terminated. This helps with the replacing of WaitForMultipleObjects
  1586. // on the PS3, since it waits for a thread to finish.
  1587. CThreadEvent m_threadEnd;
  1588. #elif defined(POSIX)
  1589. pthread_t m_threadId;
  1590. volatile pthread_t m_threadZombieId;
  1591. #endif
  1592. int m_result;
  1593. char m_szName[32];
  1594. void * m_pStackBase;
  1595. unsigned m_flags;
  1596. CThreadManualEvent m_NotSuspendedEvent;
  1597. };
  1598. // The CThread implementation needs to be inlined for performance on the PS3 - It makes a difference of more than 1ms/frame
  1599. // Since the dependency checker isn't smart enough to take an #ifdef _PS3 into account, all platforms will inline it.
  1600. #ifdef _PS3
  1601. #include "threadtools.inl"
  1602. #endif
  1603. //-----------------------------------------------------------------------------
  1604. //
  1605. // A helper class to let you sleep a thread for memory validation, you need to handle
  1606. // m_bSleepForValidate in your ::Run() call and set m_bSleepingForValidate when sleeping
  1607. //
  1608. //-----------------------------------------------------------------------------
  1609. class PLATFORM_CLASS CValidatableThread : public CThread
  1610. {
  1611. public:
  1612. CValidatableThread()
  1613. {
  1614. m_bSleepForValidate = false;
  1615. m_bSleepingForValidate = false;
  1616. }
  1617. #ifdef DBGFLAG_VALIDATE
  1618. virtual void SleepForValidate() { m_bSleepForValidate = true; }
  1619. bool BSleepingForValidate() { return m_bSleepingForValidate; }
  1620. virtual void WakeFromValidate() { m_bSleepForValidate = false; }
  1621. #endif
  1622. protected:
  1623. bool m_bSleepForValidate;
  1624. bool m_bSleepingForValidate;
  1625. };
  1626. //-----------------------------------------------------------------------------
  1627. // Simple thread class encompasses the notion of a worker thread, handing
  1628. // synchronized communication.
  1629. //-----------------------------------------------------------------------------
  1630. // These are internal reserved error results from a call attempt
  1631. enum WTCallResult_t
  1632. {
  1633. WTCR_FAIL = -1,
  1634. WTCR_TIMEOUT = -2,
  1635. WTCR_THREAD_GONE = -3,
  1636. };
  1637. class PLATFORM_CLASS CWorkerThread : public CThread
  1638. {
  1639. public:
  1640. CWorkerThread();
  1641. //-----------------------------------------------------
  1642. //
  1643. // Inter-thread communication
  1644. //
  1645. // Calls in either direction take place on the same "channel."
  1646. // Seperate functions are specified to make identities obvious
  1647. //
  1648. //-----------------------------------------------------
  1649. // Master: Signal the thread, and block for a response
  1650. int CallWorker( unsigned, unsigned timeout = TT_INFINITE, bool fBoostWorkerPriorityToMaster = true );
  1651. // Worker: Signal the thread, and block for a response
  1652. int CallMaster( unsigned, unsigned timeout = TT_INFINITE );
  1653. // Wait for the next request
  1654. bool WaitForCall( unsigned dwTimeout, unsigned *pResult = NULL );
  1655. bool WaitForCall( unsigned *pResult = NULL );
  1656. // Is there a request?
  1657. bool PeekCall( unsigned *pParam = NULL );
  1658. // Reply to the request
  1659. void Reply( unsigned );
  1660. // Wait for a reply in the case when CallWorker() with timeout != TT_INFINITE
  1661. int WaitForReply( unsigned timeout = TT_INFINITE );
  1662. // If you want to do WaitForMultipleObjects you'll need to include
  1663. // this handle in your wait list or you won't be responsive
  1664. CThreadEvent& GetCallHandle(); // (returns m_EventSend)
  1665. // Find out what the request was
  1666. unsigned GetCallParam() const;
  1667. // Boost the worker thread to the master thread, if worker thread is lesser, return old priority
  1668. int BoostPriority();
  1669. protected:
  1670. typedef uint32 ( *WaitFunc_t)( uint32 nHandles, CThreadEvent** ppHandles, int bWaitAll, uint32 timeout );
  1671. int Call( unsigned, unsigned timeout, bool fBoost, WaitFunc_t = NULL );
  1672. int WaitForReply( unsigned timeout, WaitFunc_t );
  1673. private:
  1674. CWorkerThread( const CWorkerThread & );
  1675. CWorkerThread &operator=( const CWorkerThread & );
  1676. CThreadEvent m_EventSend;
  1677. CThreadEvent m_EventComplete;
  1678. unsigned m_Param;
  1679. int m_ReturnVal;
  1680. };
  1681. // a unidirectional message queue. A queue of type T. Not especially high speed since each message
  1682. // is malloced/freed. Note that if your message class has destructors/constructors, they MUST be
  1683. // thread safe!
  1684. template<class T> class CMessageQueue
  1685. {
  1686. CThreadEvent SignalEvent; // signals presence of data
  1687. CThreadMutex QueueAccessMutex;
  1688. // the parts protected by the mutex
  1689. struct MsgNode
  1690. {
  1691. MsgNode *Next;
  1692. T Data;
  1693. };
  1694. MsgNode *Head;
  1695. MsgNode *Tail;
  1696. public:
  1697. CMessageQueue( void )
  1698. {
  1699. Head = Tail = NULL;
  1700. }
  1701. // check for a message. not 100% reliable - someone could grab the message first
  1702. bool MessageWaiting( void )
  1703. {
  1704. return ( Head != NULL );
  1705. }
  1706. void WaitMessage( T *pMsg )
  1707. {
  1708. for(;;)
  1709. {
  1710. while( ! MessageWaiting() )
  1711. SignalEvent.Wait();
  1712. QueueAccessMutex.Lock();
  1713. if (! Head )
  1714. {
  1715. // multiple readers could make this null
  1716. QueueAccessMutex.Unlock();
  1717. continue;
  1718. }
  1719. *( pMsg ) = Head->Data;
  1720. MsgNode *remove_this = Head;
  1721. Head = Head->Next;
  1722. if (! Head) // if empty, fix tail ptr
  1723. Tail = NULL;
  1724. QueueAccessMutex.Unlock();
  1725. delete remove_this;
  1726. break;
  1727. }
  1728. }
  1729. void QueueMessage( T const &Msg)
  1730. {
  1731. MsgNode *new1=new MsgNode;
  1732. new1->Data=Msg;
  1733. new1->Next=NULL;
  1734. QueueAccessMutex.Lock();
  1735. if ( Tail )
  1736. {
  1737. Tail->Next=new1;
  1738. Tail = new1;
  1739. }
  1740. else
  1741. {
  1742. Head = new1;
  1743. Tail = new1;
  1744. }
  1745. SignalEvent.Set();
  1746. QueueAccessMutex.Unlock();
  1747. }
  1748. };
  1749. //-----------------------------------------------------------------------------
  1750. //
  1751. // CThreadMutex. Inlining to reduce overhead and to allow client code
  1752. // to decide debug status (tracing)
  1753. //
  1754. //-----------------------------------------------------------------------------
  1755. #ifdef MSVC
  1756. typedef struct _RTL_CRITICAL_SECTION RTL_CRITICAL_SECTION;
  1757. typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
  1758. #ifndef _X360
  1759. extern "C"
  1760. {
  1761. void __declspec(dllimport) __stdcall InitializeCriticalSection(CRITICAL_SECTION *);
  1762. void __declspec(dllimport) __stdcall EnterCriticalSection(CRITICAL_SECTION *);
  1763. void __declspec(dllimport) __stdcall LeaveCriticalSection(CRITICAL_SECTION *);
  1764. void __declspec(dllimport) __stdcall DeleteCriticalSection(CRITICAL_SECTION *);
  1765. };
  1766. #endif
  1767. #endif
  1768. //---------------------------------------------------------
  1769. #if !defined(POSIX) || defined( _GAMECONSOLE )
  1770. inline void CThreadMutex::Lock()
  1771. {
  1772. #if defined(_PS3)
  1773. #ifndef NO_THREAD_SYNC
  1774. sys_mutex_lock( m_Mutex, 0 );
  1775. #endif
  1776. #else
  1777. #if defined( THREAD_MUTEX_TRACING_ENABLED )
  1778. uint thisThreadID = ThreadGetCurrentId();
  1779. if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) )
  1780. Msg( _T( "Thread %u about to wait for lock %p owned by %u\n" ), ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
  1781. #endif
  1782. LockSilent();
  1783. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1784. if (m_lockCount == 0)
  1785. {
  1786. // we now own it for the first time. Set owner information
  1787. m_currentOwnerID = thisThreadID;
  1788. if ( m_bTrace )
  1789. Msg( _T( "Thread %u now owns lock 0x%p\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
  1790. }
  1791. m_lockCount++;
  1792. #endif
  1793. #endif
  1794. }
  1795. //---------------------------------------------------------
  1796. inline void CThreadMutex::Unlock()
  1797. {
  1798. #if defined( _PS3 )
  1799. #ifndef NO_THREAD_SYNC
  1800. sys_mutex_unlock( m_Mutex );
  1801. #endif
  1802. #else
  1803. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1804. AssertMsg( m_lockCount >= 1, "Invalid unlock of thread lock" );
  1805. m_lockCount--;
  1806. if (m_lockCount == 0)
  1807. {
  1808. if ( m_bTrace )
  1809. Msg( _T( "Thread %u releasing lock 0x%p\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
  1810. m_currentOwnerID = 0;
  1811. }
  1812. #endif
  1813. UnlockSilent();
  1814. #endif
  1815. }
  1816. //---------------------------------------------------------
  1817. inline void CThreadMutex::LockSilent()
  1818. {
  1819. #ifdef MSVC
  1820. EnterCriticalSection((CRITICAL_SECTION *)&m_CriticalSection);
  1821. #else
  1822. DebuggerBreak(); // should not be called - not defined for this platform/compiler!!!
  1823. #endif
  1824. }
  1825. //---------------------------------------------------------
  1826. inline void CThreadMutex::UnlockSilent()
  1827. {
  1828. #ifdef MSVC
  1829. LeaveCriticalSection((CRITICAL_SECTION *)&m_CriticalSection);
  1830. #else
  1831. DebuggerBreak(); // should not be called - not defined for this platform/compiler!!!
  1832. #endif
  1833. }
  1834. //---------------------------------------------------------
  1835. inline bool CThreadMutex::AssertOwnedByCurrentThread()
  1836. {
  1837. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1838. #ifdef _WIN32
  1839. if (ThreadGetCurrentId() == m_currentOwnerID)
  1840. return true;
  1841. AssertMsg3( 0, "Expected thread %u as owner of lock 0x%p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
  1842. return false;
  1843. #elif defined( _PS3 )
  1844. return true;
  1845. #endif
  1846. #else
  1847. return true;
  1848. #endif
  1849. }
  1850. inline bool CThreadMutex::IsOwnedByCurrentThread_DebugOnly()
  1851. {
  1852. #if defined ( THREAD_MUTEX_TRACING_ENABLED ) && defined ( _WIN32 )
  1853. return ThreadGetCurrentId() == m_currentOwnerID;
  1854. #else
  1855. return true;
  1856. #endif
  1857. }
  1858. //---------------------------------------------------------
  1859. inline void CThreadMutex::SetTrace( bool bTrace )
  1860. {
  1861. #ifdef _WIN32
  1862. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1863. m_bTrace = bTrace;
  1864. #endif
  1865. #elif defined _PS3
  1866. //EAPS3
  1867. #endif
  1868. }
  1869. //---------------------------------------------------------
  1870. #elif defined(POSIX) && !defined( _GAMECONSOLE )
  1871. inline CThreadMutex::CThreadMutex()
  1872. {
  1873. // enable recursive locks as we need them
  1874. pthread_mutexattr_init( &m_Attr );
  1875. pthread_mutexattr_settype( &m_Attr, PTHREAD_MUTEX_RECURSIVE );
  1876. pthread_mutex_init( &m_Mutex, &m_Attr );
  1877. }
  1878. //---------------------------------------------------------
  1879. inline CThreadMutex::~CThreadMutex()
  1880. {
  1881. pthread_mutex_destroy( &m_Mutex );
  1882. }
  1883. //---------------------------------------------------------
  1884. inline void CThreadMutex::Lock()
  1885. {
  1886. pthread_mutex_lock( &m_Mutex );
  1887. }
  1888. //---------------------------------------------------------
  1889. inline void CThreadMutex::Unlock()
  1890. {
  1891. pthread_mutex_unlock( &m_Mutex );
  1892. }
  1893. //---------------------------------------------------------
  1894. inline void CThreadMutex::LockSilent()
  1895. {
  1896. pthread_mutex_lock( &m_Mutex );
  1897. }
  1898. //---------------------------------------------------------
  1899. inline void CThreadMutex::UnlockSilent()
  1900. {
  1901. pthread_mutex_unlock( &m_Mutex );
  1902. }
  1903. //---------------------------------------------------------
  1904. inline bool CThreadMutex::AssertOwnedByCurrentThread()
  1905. {
  1906. return true;
  1907. }
  1908. //---------------------------------------------------------
  1909. inline void CThreadMutex::SetTrace(bool fTrace)
  1910. {
  1911. }
  1912. #else
  1913. #error
  1914. #endif // POSIX
  1915. //-----------------------------------------------------------------------------
  1916. //
  1917. // CThreadRWLock inline functions
  1918. //
  1919. //-----------------------------------------------------------------------------
  1920. inline CThreadRWLock::CThreadRWLock()
  1921. : m_CanRead( true ),
  1922. m_nWriters( 0 ),
  1923. m_nActiveReaders( 0 ),
  1924. m_nPendingReaders( 0 )
  1925. {
  1926. }
  1927. inline void CThreadRWLock::LockForRead()
  1928. {
  1929. m_mutex.Lock();
  1930. if ( m_nWriters)
  1931. {
  1932. WaitForRead();
  1933. }
  1934. m_nActiveReaders++;
  1935. m_mutex.Unlock();
  1936. }
  1937. inline void CThreadRWLock::UnlockRead()
  1938. {
  1939. m_mutex.Lock();
  1940. m_nActiveReaders--;
  1941. if ( m_nActiveReaders == 0 && m_nWriters != 0 )
  1942. {
  1943. m_CanWrite.Set();
  1944. }
  1945. m_mutex.Unlock();
  1946. }
  1947. //-----------------------------------------------------------------------------
  1948. //
  1949. // CThreadSpinRWLock inline functions
  1950. //
  1951. //-----------------------------------------------------------------------------
  1952. #ifndef OLD_SPINRWLOCK
  1953. #if defined(TEST_THREAD_SPIN_RW_LOCK)
  1954. #define RWLAssert( exp ) if ( exp ) ; else DebuggerBreak();
  1955. #else
  1956. #define RWLAssert( exp ) ((void)0)
  1957. #endif
  1958. inline bool CThreadSpinRWLock::IsLockedForWrite()
  1959. {
  1960. return ( m_lockInfo.m_fWriting == 1 );
  1961. }
  1962. inline bool CThreadSpinRWLock::IsLockedForRead()
  1963. {
  1964. return ( m_lockInfo.m_nReaders > 0 );
  1965. }
  1966. FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite()
  1967. {
  1968. volatile LockInfo_t &curValue = m_lockInfo;
  1969. if ( !( curValue.m_i32 & 0x00010000 ) && ThreadInterlockedAssignIf( &curValue.m_i32, 0x00010000, 0 ) )
  1970. {
  1971. ThreadMemoryBarrier();
  1972. RWLAssert( m_iWriteDepth == 0 && m_writerId == 0 );
  1973. m_writerId = ThreadGetCurrentId();
  1974. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  1975. m_iWriteDepth++;
  1976. #endif
  1977. return true;
  1978. }
  1979. return false;
  1980. }
  1981. inline bool CThreadSpinRWLock::TryLockForWrite_UnforcedInline()
  1982. {
  1983. if ( TryLockForWrite() )
  1984. {
  1985. return true;
  1986. }
  1987. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  1988. if ( m_writerId != ThreadGetCurrentId() )
  1989. {
  1990. return false;
  1991. }
  1992. m_iWriteDepth++;
  1993. return true;
  1994. #else
  1995. return false;
  1996. #endif
  1997. }
  1998. FORCEINLINE void CThreadSpinRWLock::LockForWrite()
  1999. {
  2000. if ( !TryLockForWrite() )
  2001. {
  2002. SpinLockForWrite();
  2003. }
  2004. }
  2005. FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
  2006. {
  2007. volatile LockInfo_t &curValue = m_lockInfo;
  2008. if ( !( curValue.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting
  2009. {
  2010. LockInfo_t oldValue;
  2011. LockInfo_t newValue;
  2012. oldValue.m_i32 = ( curValue.m_i32 & 0xffff );
  2013. newValue.m_i32 = oldValue.m_i32 + 1;
  2014. if ( ThreadInterlockedAssignIf( &m_lockInfo.m_i32, newValue.m_i32, oldValue.m_i32 ) )
  2015. {
  2016. ThreadMemoryBarrier();
  2017. RWLAssert( m_lockInfo.m_fWriting == 0 );
  2018. return true;
  2019. }
  2020. }
  2021. return false;
  2022. }
  2023. inline bool CThreadSpinRWLock::TryLockForRead_UnforcedInline()
  2024. {
  2025. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  2026. if ( m_lockInfo.m_i32 & 0x00010000 ) // m_lockInfo.m_fWriting
  2027. {
  2028. if ( m_writerId == ThreadGetCurrentId() )
  2029. {
  2030. m_lockInfo.m_nReaders++;
  2031. return true;
  2032. }
  2033. return false;
  2034. }
  2035. #endif
  2036. return TryLockForRead();
  2037. }
  2038. FORCEINLINE void CThreadSpinRWLock::LockForRead()
  2039. {
  2040. if ( !TryLockForRead() )
  2041. {
  2042. SpinLockForRead();
  2043. }
  2044. }
  2045. FORCEINLINE void CThreadSpinRWLock::UnlockWrite()
  2046. {
  2047. RWLAssert( m_writerId == ThreadGetCurrentId() );
  2048. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  2049. if ( --m_iWriteDepth == 0 )
  2050. #endif
  2051. {
  2052. m_writerId = 0;
  2053. ThreadMemoryBarrier();
  2054. m_lockInfo.m_i32 = 0;
  2055. }
  2056. }
  2057. #ifndef REENTRANT_THREAD_SPIN_RW_LOCK
  2058. FORCEINLINE
  2059. #else
  2060. inline
  2061. #endif
  2062. void CThreadSpinRWLock::UnlockRead()
  2063. {
  2064. RWLAssert( m_writerId == 0 || ( m_writerId == ThreadGetCurrentId() && m_lockInfo.m_fWriting ) );
  2065. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  2066. if ( !( m_lockInfo.m_i32 & 0x00010000 ) ) // !m_lockInfo.m_fWriting
  2067. #endif
  2068. {
  2069. ThreadMemoryBarrier();
  2070. ThreadInterlockedDecrement( &m_lockInfo.m_i32 );
  2071. RWLAssert( m_writerId == 0 && !m_lockInfo.m_fWriting );
  2072. }
  2073. #ifdef REENTRANT_THREAD_SPIN_RW_LOCK
  2074. else if ( m_writerId == ThreadGetCurrentId() )
  2075. {
  2076. m_lockInfo.m_nReaders--;
  2077. }
  2078. else
  2079. {
  2080. RWLAssert( 0 );
  2081. }
  2082. #endif
  2083. }
  2084. #else
  2085. /* (commented out to reduce distraction in colorized editor, remove entirely when new implementation settles)
  2086. inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand )
  2087. {
  2088. // Note: using unions guarantees no aliasing bugs. Casting structures through *(int64*)&
  2089. // may create hard-to-catch bugs because when you do that, compiler doesn't know that the newly computed pointer
  2090. // is actually aliased with LockInfo_t structure. It's rarely a problem in practice, but when it is, it's a royal pain to debug.
  2091. return ThreadInterlockedAssignIf64( &m_lockInfo.m_i64, newValue.m_i64, comperand.m_i64 );
  2092. }
  2093. FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId )
  2094. {
  2095. // In order to grab a write lock, there can be no readers and no owners of the write lock
  2096. if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) )
  2097. {
  2098. return false;
  2099. }
  2100. static const LockInfo_t oldValue = { {0, 0} };
  2101. LockInfo_t newValue = { { threadId, 0 } };
  2102. if ( AssignIf( newValue, oldValue ) )
  2103. {
  2104. ThreadMemoryBarrier();
  2105. return true;
  2106. }
  2107. return false;
  2108. }
  2109. inline bool CThreadSpinRWLock::TryLockForWrite()
  2110. {
  2111. m_nWriters++;
  2112. if ( !TryLockForWrite( ThreadGetCurrentId() ) )
  2113. {
  2114. m_nWriters--;
  2115. return false;
  2116. }
  2117. return true;
  2118. }
  2119. FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
  2120. {
  2121. if ( m_nWriters != 0 )
  2122. {
  2123. return false;
  2124. }
  2125. // In order to grab a write lock, the number of readers must not change and no thread can own the write
  2126. LockInfo_t oldValue;
  2127. LockInfo_t newValue;
  2128. if( IsX360() || IsPS3() )
  2129. {
  2130. // this is the code equivalent to original code (see below) that doesn't cause LHS on Xbox360
  2131. // WARNING: This code assumes BIG Endian CPU
  2132. oldValue.m_i64 = uint32( m_lockInfo.m_nReaders );
  2133. newValue.m_i64 = oldValue.m_i64 + 1; // NOTE: when we have -1 (or 0xFFFFFFFF) readers, this will result in non-equivalent code
  2134. }
  2135. else
  2136. {
  2137. // this is the original code that worked here for a while
  2138. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  2139. oldValue.m_writerId = 0;
  2140. newValue.m_nReaders = oldValue.m_nReaders + 1;
  2141. newValue.m_writerId = 0;
  2142. }
  2143. if ( AssignIf( newValue, oldValue ) )
  2144. {
  2145. ThreadMemoryBarrier();
  2146. return true;
  2147. }
  2148. return false;
  2149. }
  2150. inline void CThreadSpinRWLock::LockForWrite()
  2151. {
  2152. const uint32 threadId = ThreadGetCurrentId();
  2153. m_nWriters++;
  2154. if ( !TryLockForWrite( threadId ) )
  2155. {
  2156. ThreadPause();
  2157. SpinLockForWrite( threadId );
  2158. }
  2159. }
  2160. */
  2161. #endif
  2162. // read data from a memory address
  2163. template<class T> FORCEINLINE T ReadVolatileMemory( T const *pPtr )
  2164. {
  2165. volatile const T * pVolatilePtr = ( volatile const T * ) pPtr;
  2166. return *pVolatilePtr;
  2167. }
  2168. //-----------------------------------------------------------------------------
  2169. #if defined( _WIN32 )
  2170. #pragma warning(pop)
  2171. #endif
  2172. #if defined( _PS3 )
  2173. BOOL SetEvent( CThreadEvent *pEvent );
  2174. BOOL ResetEvent( CThreadEvent *pEvent );
  2175. DWORD WaitForMultipleObjects(DWORD nCount, CThreadEvent **lppHandles, BOOL bWaitAll, DWORD dwMilliseconds );
  2176. #endif // _PS3
  2177. #endif // THREADTOOLS_H