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

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