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.

2404 lines
55 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_tier0.h"
  7. #include "tier1/strtools.h"
  8. #include "tier0/dynfunction.h"
  9. #if defined( _WIN32 ) && !defined( _X360 )
  10. #define WIN32_LEAN_AND_MEAN
  11. #include <windows.h>
  12. #endif
  13. #ifdef _WIN32
  14. #include <process.h>
  15. #ifdef IS_WINDOWS_PC
  16. #include <Mmsystem.h>
  17. #pragma comment(lib, "winmm.lib")
  18. #endif // IS_WINDOWS_PC
  19. #elif defined(POSIX)
  20. #if !defined(OSX)
  21. #include <sys/fcntl.h>
  22. #include <sys/unistd.h>
  23. #define sem_unlink( arg )
  24. #define OS_TO_PTHREAD(x) (x)
  25. #else
  26. #define pthread_yield pthread_yield_np
  27. #include <mach/thread_act.h>
  28. #include <mach/mach.h>
  29. #define OS_TO_PTHREAD(x) pthread_from_mach_thread_np( x )
  30. #endif // !OSX
  31. #ifdef LINUX
  32. #include <dlfcn.h> // RTLD_NEXT
  33. #endif
  34. typedef int (*PTHREAD_START_ROUTINE)(
  35. void *lpThreadParameter
  36. );
  37. typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
  38. #include <sched.h>
  39. #include <exception>
  40. #include <errno.h>
  41. #include <signal.h>
  42. #include <pthread.h>
  43. #include <sys/time.h>
  44. #define GetLastError() errno
  45. typedef void *LPVOID;
  46. #endif
  47. #include "tier0/valve_minmax_off.h"
  48. #include <memory>
  49. #include "tier0/valve_minmax_on.h"
  50. #include "tier0/threadtools.h"
  51. #include "tier0/vcrmode.h"
  52. #ifdef _X360
  53. #include "xbox/xbox_win32stubs.h"
  54. #endif
  55. #include "tier0/vprof_telemetry.h"
  56. // Must be last header...
  57. #include "tier0/memdbgon.h"
  58. #define THREADS_DEBUG 1
  59. // Need to ensure initialized before other clients call in for main thread ID
  60. #ifdef _WIN32
  61. #pragma warning(disable:4073)
  62. #pragma init_seg(lib)
  63. #endif
  64. #ifdef _WIN32
  65. ASSERT_INVARIANT(TT_SIZEOF_CRITICALSECTION == sizeof(CRITICAL_SECTION));
  66. ASSERT_INVARIANT(TT_INFINITE == INFINITE);
  67. #endif
  68. //-----------------------------------------------------------------------------
  69. // Simple thread functions.
  70. // Because _beginthreadex uses stdcall, we need to convert to cdecl
  71. //-----------------------------------------------------------------------------
  72. struct ThreadProcInfo_t
  73. {
  74. ThreadProcInfo_t( ThreadFunc_t pfnThread, void *pParam )
  75. : pfnThread( pfnThread),
  76. pParam( pParam )
  77. {
  78. }
  79. ThreadFunc_t pfnThread;
  80. void * pParam;
  81. };
  82. //---------------------------------------------------------
  83. #ifdef _WIN32
  84. static unsigned __stdcall ThreadProcConvert( void *pParam )
  85. #elif defined(POSIX)
  86. static void *ThreadProcConvert( void *pParam )
  87. #else
  88. #error
  89. #endif
  90. {
  91. ThreadProcInfo_t info = *((ThreadProcInfo_t *)pParam);
  92. delete ((ThreadProcInfo_t *)pParam);
  93. #ifdef _WIN32
  94. return (*info.pfnThread)(info.pParam);
  95. #elif defined(POSIX)
  96. return (void *)(*info.pfnThread)(info.pParam);
  97. #else
  98. #error
  99. #endif
  100. }
  101. //---------------------------------------------------------
  102. ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, ThreadId_t *pID, unsigned stackSize )
  103. {
  104. #ifdef _WIN32
  105. ThreadId_t idIgnored;
  106. if ( !pID )
  107. pID = &idIgnored;
  108. HANDLE h = VCRHook_CreateThread(NULL, stackSize, (LPTHREAD_START_ROUTINE)ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), CREATE_SUSPENDED, pID);
  109. if ( h != INVALID_HANDLE_VALUE )
  110. {
  111. Plat_ApplyHardwareDataBreakpointsToNewThread( *pID );
  112. ResumeThread( h );
  113. }
  114. return (ThreadHandle_t)h;
  115. #elif defined(POSIX)
  116. pthread_t tid;
  117. // If we need to create threads that are detached right out of the gate, we would need to do something like this:
  118. // pthread_attr_t attr;
  119. // int rc = pthread_attr_init(&attr);
  120. // rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  121. // ... pthread_create( &tid, &attr, ... ) ...
  122. // rc = pthread_attr_destroy(&attr);
  123. // ... pthread_join will now fail
  124. int ret = pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) );
  125. if ( ret )
  126. {
  127. // There are only PTHREAD_THREADS_MAX number of threads, and we're probably leaking handles if ret == EAGAIN here?
  128. Error( "CreateSimpleThread: pthread_create failed. Someone not calling pthread_detach() or pthread_join. Ret:%d\n", ret );
  129. }
  130. if ( pID )
  131. *pID = (ThreadId_t)tid;
  132. Plat_ApplyHardwareDataBreakpointsToNewThread( (long unsigned int)tid );
  133. return (ThreadHandle_t)tid;
  134. #endif
  135. }
  136. ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigned stackSize )
  137. {
  138. return CreateSimpleThread( pfnThread, pParam, NULL, stackSize );
  139. }
  140. PLATFORM_INTERFACE void ThreadDetach( ThreadHandle_t hThread )
  141. {
  142. #if defined( POSIX )
  143. // The resources of this thread will be freed immediately when it terminates,
  144. // instead of waiting for another thread to perform PTHREAD_JOIN.
  145. pthread_t tid = ( pthread_t )hThread;
  146. pthread_detach( tid );
  147. #endif
  148. }
  149. bool ReleaseThreadHandle( ThreadHandle_t hThread )
  150. {
  151. #ifdef _WIN32
  152. return ( CloseHandle( hThread ) != 0 );
  153. #else
  154. return true;
  155. #endif
  156. }
  157. //-----------------------------------------------------------------------------
  158. //
  159. // Wrappers for other simple threading operations
  160. //
  161. //-----------------------------------------------------------------------------
  162. void ThreadSleep(unsigned nMilliseconds)
  163. {
  164. #ifdef _WIN32
  165. #ifdef IS_WINDOWS_PC
  166. static bool bInitialized = false;
  167. if ( !bInitialized )
  168. {
  169. bInitialized = true;
  170. // Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
  171. // some other value depending on hardware and software) so that we can
  172. // use Sleep( 1 ) to avoid wasting CPU time without missing our frame
  173. // rate.
  174. timeBeginPeriod( 1 );
  175. }
  176. #endif // IS_WINDOWS_PC
  177. Sleep( nMilliseconds );
  178. #elif defined(POSIX)
  179. usleep( nMilliseconds * 1000 );
  180. #endif
  181. }
  182. //-----------------------------------------------------------------------------
  183. #ifndef ThreadGetCurrentId
  184. uint ThreadGetCurrentId()
  185. {
  186. #ifdef _WIN32
  187. return GetCurrentThreadId();
  188. #elif defined(POSIX)
  189. return (uint)pthread_self();
  190. #endif
  191. }
  192. #endif
  193. //-----------------------------------------------------------------------------
  194. ThreadHandle_t ThreadGetCurrentHandle()
  195. {
  196. #ifdef _WIN32
  197. return (ThreadHandle_t)GetCurrentThread();
  198. #elif defined(POSIX)
  199. return (ThreadHandle_t)pthread_self();
  200. #endif
  201. }
  202. // On PS3, this will return true for zombie threads
  203. bool ThreadIsThreadIdRunning( ThreadId_t uThreadId )
  204. {
  205. #ifdef _WIN32
  206. bool bRunning = true;
  207. HANDLE hThread = ::OpenThread( THREAD_QUERY_INFORMATION , false, uThreadId );
  208. if ( hThread )
  209. {
  210. DWORD dwExitCode;
  211. if( !::GetExitCodeThread( hThread, &dwExitCode ) || dwExitCode != STILL_ACTIVE )
  212. bRunning = false;
  213. CloseHandle( hThread );
  214. }
  215. else
  216. {
  217. bRunning = false;
  218. }
  219. return bRunning;
  220. #elif defined( _PS3 )
  221. // will return CELL_OK for zombie threads
  222. int priority;
  223. return (sys_ppu_thread_get_priority( uThreadId, &priority ) == CELL_OK );
  224. #elif defined(POSIX)
  225. pthread_t thread = OS_TO_PTHREAD(uThreadId);
  226. if ( thread )
  227. {
  228. int iResult = pthread_kill( thread, 0 );
  229. if ( iResult == 0 )
  230. return true;
  231. }
  232. else
  233. {
  234. // We really ought not to be passing NULL in to here
  235. AssertMsg( false, "ThreadIsThreadIdRunning received a null thread ID" );
  236. }
  237. return false;
  238. #endif
  239. }
  240. //-----------------------------------------------------------------------------
  241. int ThreadGetPriority( ThreadHandle_t hThread )
  242. {
  243. if ( !hThread )
  244. {
  245. hThread = ThreadGetCurrentHandle();
  246. }
  247. #ifdef _WIN32
  248. return ::GetThreadPriority( (HANDLE)hThread );
  249. #else
  250. struct sched_param thread_param;
  251. int policy;
  252. pthread_getschedparam( (pthread_t)hThread, &policy, &thread_param );
  253. return thread_param.sched_priority;
  254. #endif
  255. }
  256. //-----------------------------------------------------------------------------
  257. bool ThreadSetPriority( ThreadHandle_t hThread, int priority )
  258. {
  259. if ( !hThread )
  260. {
  261. hThread = ThreadGetCurrentHandle();
  262. }
  263. #ifdef _WIN32
  264. return ( SetThreadPriority(hThread, priority) != 0 );
  265. #elif defined(POSIX)
  266. struct sched_param thread_param;
  267. thread_param.sched_priority = priority;
  268. pthread_setschedparam( (pthread_t)hThread, SCHED_OTHER, &thread_param );
  269. return true;
  270. #endif
  271. }
  272. //-----------------------------------------------------------------------------
  273. void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinityMask )
  274. {
  275. if ( !hThread )
  276. {
  277. hThread = ThreadGetCurrentHandle();
  278. }
  279. #ifdef _WIN32
  280. SetThreadAffinityMask( hThread, nAffinityMask );
  281. #elif defined(POSIX)
  282. // cpu_set_t cpuSet;
  283. // CPU_ZERO( cpuSet );
  284. // for( int i = 0 ; i < 32; i++ )
  285. // if ( nAffinityMask & ( 1 << i ) )
  286. // CPU_SET( cpuSet, i );
  287. // sched_setaffinity( hThread, sizeof( cpuSet ), &cpuSet );
  288. #endif
  289. }
  290. //-----------------------------------------------------------------------------
  291. uint InitMainThread()
  292. {
  293. #ifndef LINUX
  294. // Skip doing the setname on Linux for the main thread. Here is why...
  295. // From Pierre-Loup e-mail about why pthread_setname_np() on the main thread
  296. // in Linux will cause some tools to display "MainThrd" as the executable name:
  297. //
  298. // You have two things in procfs, comm and cmdline. Each of the threads have
  299. // a different `comm`, which is the value you set through pthread_setname_np
  300. // or prctl(PR_SET_NAME). Top can either display cmdline or comm; it
  301. // switched to display comm by default; htop still displays cmdline by
  302. // default. Top -c will output cmdline rather than comm.
  303. //
  304. // If you press 'H' while top is running it will display each thread as a
  305. // separate process, so you will have different entries for MainThrd,
  306. // MatQueue0, etc with their own CPU usage. But when that mode isn't enabled
  307. // it just displays the 'comm' name from the first thread.
  308. ThreadSetDebugName( "MainThrd" );
  309. #endif
  310. #ifdef _WIN32
  311. return ThreadGetCurrentId();
  312. #elif defined(POSIX)
  313. return (uint)pthread_self();
  314. #endif
  315. }
  316. uint g_ThreadMainThreadID = InitMainThread();
  317. bool ThreadInMainThread()
  318. {
  319. return ( ThreadGetCurrentId() == g_ThreadMainThreadID );
  320. }
  321. //-----------------------------------------------------------------------------
  322. void DeclareCurrentThreadIsMainThread()
  323. {
  324. g_ThreadMainThreadID = ThreadGetCurrentId();
  325. }
  326. bool ThreadJoin( ThreadHandle_t hThread, unsigned timeout )
  327. {
  328. // You should really never be calling this with a NULL thread handle. If you
  329. // are then that probably implies a race condition or threading misunderstanding.
  330. Assert( hThread );
  331. if ( !hThread )
  332. {
  333. return false;
  334. }
  335. #ifdef _WIN32
  336. DWORD dwWait = VCRHook_WaitForSingleObject((HANDLE)hThread, timeout);
  337. if ( dwWait == WAIT_TIMEOUT)
  338. return false;
  339. if ( dwWait != WAIT_OBJECT_0 && ( dwWait != WAIT_FAILED && GetLastError() != 0 ) )
  340. {
  341. Assert( 0 );
  342. return false;
  343. }
  344. #elif defined(POSIX)
  345. if ( pthread_join( (pthread_t)hThread, NULL ) != 0 )
  346. return false;
  347. #endif
  348. return true;
  349. }
  350. #ifdef RAD_TELEMETRY_ENABLED
  351. void TelemetryThreadSetDebugName( ThreadId_t id, const char *pszName );
  352. #endif
  353. //-----------------------------------------------------------------------------
  354. void ThreadSetDebugName( ThreadId_t id, const char *pszName )
  355. {
  356. if( !pszName )
  357. return;
  358. #ifdef RAD_TELEMETRY_ENABLED
  359. TelemetryThreadSetDebugName( id, pszName );
  360. #endif
  361. #ifdef _WIN32
  362. if ( Plat_IsInDebugSession() )
  363. {
  364. #define MS_VC_EXCEPTION 0x406d1388
  365. typedef struct tagTHREADNAME_INFO
  366. {
  367. DWORD dwType; // must be 0x1000
  368. LPCSTR szName; // pointer to name (in same addr space)
  369. DWORD dwThreadID; // thread ID (-1 caller thread)
  370. DWORD dwFlags; // reserved for future use, most be zero
  371. } THREADNAME_INFO;
  372. THREADNAME_INFO info;
  373. info.dwType = 0x1000;
  374. info.szName = pszName;
  375. info.dwThreadID = id;
  376. info.dwFlags = 0;
  377. __try
  378. {
  379. RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
  380. }
  381. __except (EXCEPTION_CONTINUE_EXECUTION)
  382. {
  383. }
  384. }
  385. #elif defined( _LINUX )
  386. // As of glibc v2.12, we can use pthread_setname_np.
  387. typedef int (pthread_setname_np_func)(pthread_t, const char *);
  388. static pthread_setname_np_func *s_pthread_setname_np_func = (pthread_setname_np_func *)dlsym(RTLD_DEFAULT, "pthread_setname_np");
  389. if ( s_pthread_setname_np_func )
  390. {
  391. if ( id == (uint32)-1 )
  392. id = pthread_self();
  393. /*
  394. pthread_setname_np() in phthread_setname.c has the following code:
  395. #define TASK_COMM_LEN 16
  396. size_t name_len = strlen (name);
  397. if (name_len >= TASK_COMM_LEN)
  398. return ERANGE;
  399. So we need to truncate the threadname to 16 or the call will just fail.
  400. */
  401. char szThreadName[ 16 ];
  402. strncpy( szThreadName, pszName, ARRAYSIZE( szThreadName ) );
  403. szThreadName[ ARRAYSIZE( szThreadName ) - 1 ] = 0;
  404. (*s_pthread_setname_np_func)( id, szThreadName );
  405. }
  406. #endif
  407. }
  408. //-----------------------------------------------------------------------------
  409. #ifdef _WIN32
  410. ASSERT_INVARIANT( TW_FAILED == WAIT_FAILED );
  411. ASSERT_INVARIANT( TW_TIMEOUT == WAIT_TIMEOUT );
  412. ASSERT_INVARIANT( WAIT_OBJECT_0 == 0 );
  413. int ThreadWaitForObjects( int nEvents, const HANDLE *pHandles, bool bWaitAll, unsigned timeout )
  414. {
  415. return VCRHook_WaitForMultipleObjects( nEvents, pHandles, bWaitAll, timeout );
  416. }
  417. #endif
  418. //-----------------------------------------------------------------------------
  419. // Used to thread LoadLibrary on the 360
  420. //-----------------------------------------------------------------------------
  421. static ThreadedLoadLibraryFunc_t s_ThreadedLoadLibraryFunc = 0;
  422. PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func )
  423. {
  424. s_ThreadedLoadLibraryFunc = func;
  425. }
  426. PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc()
  427. {
  428. return s_ThreadedLoadLibraryFunc;
  429. }
  430. //-----------------------------------------------------------------------------
  431. //
  432. //-----------------------------------------------------------------------------
  433. CThreadSyncObject::CThreadSyncObject()
  434. #ifdef _WIN32
  435. : m_hSyncObject( NULL ), m_bCreatedHandle(false)
  436. #elif defined(POSIX)
  437. : m_bInitalized( false )
  438. #endif
  439. {
  440. }
  441. //---------------------------------------------------------
  442. CThreadSyncObject::~CThreadSyncObject()
  443. {
  444. #ifdef _WIN32
  445. if ( m_hSyncObject && m_bCreatedHandle )
  446. {
  447. if ( !CloseHandle(m_hSyncObject) )
  448. {
  449. Assert( 0 );
  450. }
  451. }
  452. #elif defined(POSIX)
  453. if ( m_bInitalized )
  454. {
  455. pthread_cond_destroy( &m_Condition );
  456. pthread_mutex_destroy( &m_Mutex );
  457. m_bInitalized = false;
  458. }
  459. #endif
  460. }
  461. //---------------------------------------------------------
  462. bool CThreadSyncObject::operator!() const
  463. {
  464. #ifdef _WIN32
  465. return !m_hSyncObject;
  466. #elif defined(POSIX)
  467. return !m_bInitalized;
  468. #endif
  469. }
  470. //---------------------------------------------------------
  471. void CThreadSyncObject::AssertUseable()
  472. {
  473. #ifdef THREADS_DEBUG
  474. #ifdef _WIN32
  475. AssertMsg( m_hSyncObject, "Thread synchronization object is unuseable" );
  476. #elif defined(POSIX)
  477. AssertMsg( m_bInitalized, "Thread synchronization object is unuseable" );
  478. #endif
  479. #endif
  480. }
  481. //---------------------------------------------------------
  482. bool CThreadSyncObject::Wait( uint32 dwTimeout )
  483. {
  484. #ifdef THREADS_DEBUG
  485. AssertUseable();
  486. #endif
  487. #ifdef _WIN32
  488. return ( VCRHook_WaitForSingleObject( m_hSyncObject, dwTimeout ) == WAIT_OBJECT_0 );
  489. #elif defined(POSIX)
  490. pthread_mutex_lock( &m_Mutex );
  491. bool bRet = false;
  492. if ( m_cSet > 0 )
  493. {
  494. bRet = true;
  495. m_bWakeForEvent = false;
  496. }
  497. else
  498. {
  499. volatile int ret = 0;
  500. while ( !m_bWakeForEvent && ret != ETIMEDOUT )
  501. {
  502. struct timeval tv;
  503. gettimeofday( &tv, NULL );
  504. volatile struct timespec tm;
  505. uint64 actualTimeout = dwTimeout;
  506. if ( dwTimeout == TT_INFINITE && m_bManualReset )
  507. actualTimeout = 10; // just wait 10 msec at most for manual reset events and loop instead
  508. volatile uint64 nNanoSec = (uint64)tv.tv_usec*1000 + (uint64)actualTimeout*1000000;
  509. tm.tv_sec = tv.tv_sec + nNanoSec /1000000000;
  510. tm.tv_nsec = nNanoSec % 1000000000;
  511. do
  512. {
  513. ret = pthread_cond_timedwait( &m_Condition, &m_Mutex, (const timespec *)&tm );
  514. }
  515. while( ret == EINTR );
  516. bRet = ( ret == 0 );
  517. if ( m_bManualReset )
  518. {
  519. if ( m_cSet )
  520. break;
  521. if ( dwTimeout == TT_INFINITE && ret == ETIMEDOUT )
  522. ret = 0; // force the loop to spin back around
  523. }
  524. }
  525. if ( bRet )
  526. m_bWakeForEvent = false;
  527. }
  528. if ( !m_bManualReset && bRet )
  529. m_cSet = 0;
  530. pthread_mutex_unlock( &m_Mutex );
  531. return bRet;
  532. #endif
  533. }
  534. //-----------------------------------------------------------------------------
  535. //
  536. //-----------------------------------------------------------------------------
  537. CThreadEvent::CThreadEvent( bool bManualReset )
  538. {
  539. #ifdef _WIN32
  540. m_hSyncObject = CreateEvent( NULL, bManualReset, FALSE, NULL );
  541. m_bCreatedHandle = true;
  542. AssertMsg1(m_hSyncObject, "Failed to create event (error 0x%x)", GetLastError() );
  543. #elif defined( POSIX )
  544. pthread_mutexattr_t Attr;
  545. pthread_mutexattr_init( &Attr );
  546. pthread_mutex_init( &m_Mutex, &Attr );
  547. pthread_mutexattr_destroy( &Attr );
  548. pthread_cond_init( &m_Condition, NULL );
  549. m_bInitalized = true;
  550. m_cSet = 0;
  551. m_bWakeForEvent = false;
  552. m_bManualReset = bManualReset;
  553. #else
  554. #error "Implement me"
  555. #endif
  556. }
  557. #ifdef _WIN32
  558. CThreadEvent::CThreadEvent( HANDLE hHandle )
  559. {
  560. m_hSyncObject = hHandle;
  561. m_bCreatedHandle = false;
  562. AssertMsg(m_hSyncObject, "Null event passed into constructor" );
  563. }
  564. #endif
  565. //-----------------------------------------------------------------------------
  566. //
  567. //-----------------------------------------------------------------------------
  568. //---------------------------------------------------------
  569. bool CThreadEvent::Set()
  570. {
  571. AssertUseable();
  572. #ifdef _WIN32
  573. return ( SetEvent( m_hSyncObject ) != 0 );
  574. #elif defined(POSIX)
  575. pthread_mutex_lock( &m_Mutex );
  576. m_cSet = 1;
  577. m_bWakeForEvent = true;
  578. int ret = pthread_cond_signal( &m_Condition );
  579. pthread_mutex_unlock( &m_Mutex );
  580. return ret == 0;
  581. #endif
  582. }
  583. //---------------------------------------------------------
  584. bool CThreadEvent::Reset()
  585. {
  586. #ifdef THREADS_DEBUG
  587. AssertUseable();
  588. #endif
  589. #ifdef _WIN32
  590. return ( ResetEvent( m_hSyncObject ) != 0 );
  591. #elif defined(POSIX)
  592. pthread_mutex_lock( &m_Mutex );
  593. m_cSet = 0;
  594. m_bWakeForEvent = false;
  595. pthread_mutex_unlock( &m_Mutex );
  596. return true;
  597. #endif
  598. }
  599. //---------------------------------------------------------
  600. bool CThreadEvent::Check()
  601. {
  602. #ifdef THREADS_DEBUG
  603. AssertUseable();
  604. #endif
  605. return Wait( 0 );
  606. }
  607. bool CThreadEvent::Wait( uint32 dwTimeout )
  608. {
  609. return CThreadSyncObject::Wait( dwTimeout );
  610. }
  611. #ifdef _WIN32
  612. //-----------------------------------------------------------------------------
  613. //
  614. // CThreadSemaphore
  615. //
  616. // To get Posix implementation, try http://www-128.ibm.com/developerworks/eserver/library/es-win32linux-sem.html
  617. //
  618. //-----------------------------------------------------------------------------
  619. CThreadSemaphore::CThreadSemaphore( long initialValue, long maxValue )
  620. {
  621. if ( maxValue )
  622. {
  623. AssertMsg( maxValue > 0, "Invalid max value for semaphore" );
  624. AssertMsg( initialValue >= 0 && initialValue <= maxValue, "Invalid initial value for semaphore" );
  625. m_hSyncObject = CreateSemaphore( NULL, initialValue, maxValue, NULL );
  626. AssertMsg1(m_hSyncObject, "Failed to create semaphore (error 0x%x)", GetLastError());
  627. }
  628. else
  629. {
  630. m_hSyncObject = NULL;
  631. }
  632. }
  633. //---------------------------------------------------------
  634. bool CThreadSemaphore::Release( long releaseCount, long *pPreviousCount )
  635. {
  636. #ifdef THRDTOOL_DEBUG
  637. AssertUseable();
  638. #endif
  639. return ( ReleaseSemaphore( m_hSyncObject, releaseCount, pPreviousCount ) != 0 );
  640. }
  641. //-----------------------------------------------------------------------------
  642. //
  643. //-----------------------------------------------------------------------------
  644. CThreadFullMutex::CThreadFullMutex( bool bEstablishInitialOwnership, const char *pszName )
  645. {
  646. m_hSyncObject = CreateMutex( NULL, bEstablishInitialOwnership, pszName );
  647. AssertMsg1( m_hSyncObject, "Failed to create mutex (error 0x%x)", GetLastError() );
  648. }
  649. //---------------------------------------------------------
  650. bool CThreadFullMutex::Release()
  651. {
  652. #ifdef THRDTOOL_DEBUG
  653. AssertUseable();
  654. #endif
  655. return ( ReleaseMutex( m_hSyncObject ) != 0 );
  656. }
  657. #endif
  658. //-----------------------------------------------------------------------------
  659. //
  660. //-----------------------------------------------------------------------------
  661. CThreadLocalBase::CThreadLocalBase()
  662. {
  663. #ifdef _WIN32
  664. m_index = TlsAlloc();
  665. AssertMsg( m_index != 0xFFFFFFFF, "Bad thread local" );
  666. if ( m_index == 0xFFFFFFFF )
  667. Error( "Out of thread local storage!\n" );
  668. #elif defined(POSIX)
  669. if ( pthread_key_create( &m_index, NULL ) != 0 )
  670. Error( "Out of thread local storage!\n" );
  671. #endif
  672. }
  673. //---------------------------------------------------------
  674. CThreadLocalBase::~CThreadLocalBase()
  675. {
  676. #ifdef _WIN32
  677. if ( m_index != 0xFFFFFFFF )
  678. TlsFree( m_index );
  679. m_index = 0xFFFFFFFF;
  680. #elif defined(POSIX)
  681. pthread_key_delete( m_index );
  682. #endif
  683. }
  684. //---------------------------------------------------------
  685. void * CThreadLocalBase::Get() const
  686. {
  687. #ifdef _WIN32
  688. if ( m_index != 0xFFFFFFFF )
  689. return TlsGetValue( m_index );
  690. AssertMsg( 0, "Bad thread local" );
  691. return NULL;
  692. #elif defined(POSIX)
  693. void *value = pthread_getspecific( m_index );
  694. return value;
  695. #endif
  696. }
  697. //---------------------------------------------------------
  698. void CThreadLocalBase::Set( void *value )
  699. {
  700. #ifdef _WIN32
  701. if (m_index != 0xFFFFFFFF)
  702. TlsSetValue(m_index, value);
  703. else
  704. AssertMsg( 0, "Bad thread local" );
  705. #elif defined(POSIX)
  706. if ( pthread_setspecific( m_index, value ) != 0 )
  707. AssertMsg( 0, "Bad thread local" );
  708. #endif
  709. }
  710. //-----------------------------------------------------------------------------
  711. //-----------------------------------------------------------------------------
  712. #ifdef _WIN32
  713. #ifdef _X360
  714. #define TO_INTERLOCK_PARAM(p) ((long *)p)
  715. #define TO_INTERLOCK_PTR_PARAM(p) ((void **)p)
  716. #else
  717. #define TO_INTERLOCK_PARAM(p) (p)
  718. #define TO_INTERLOCK_PTR_PARAM(p) (p)
  719. #endif
  720. #ifndef USE_INTRINSIC_INTERLOCKED
  721. long ThreadInterlockedIncrement( long volatile *pDest )
  722. {
  723. Assert( (size_t)pDest % 4 == 0 );
  724. return InterlockedIncrement( TO_INTERLOCK_PARAM(pDest) );
  725. }
  726. long ThreadInterlockedDecrement( long volatile *pDest )
  727. {
  728. Assert( (size_t)pDest % 4 == 0 );
  729. return InterlockedDecrement( TO_INTERLOCK_PARAM(pDest) );
  730. }
  731. long ThreadInterlockedExchange( long volatile *pDest, long value )
  732. {
  733. Assert( (size_t)pDest % 4 == 0 );
  734. return InterlockedExchange( TO_INTERLOCK_PARAM(pDest), value );
  735. }
  736. long ThreadInterlockedExchangeAdd( long volatile *pDest, long value )
  737. {
  738. Assert( (size_t)pDest % 4 == 0 );
  739. return InterlockedExchangeAdd( TO_INTERLOCK_PARAM(pDest), value );
  740. }
  741. long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand )
  742. {
  743. Assert( (size_t)pDest % 4 == 0 );
  744. return InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand );
  745. }
  746. bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand )
  747. {
  748. Assert( (size_t)pDest % 4 == 0 );
  749. #if !(defined(_WIN64) || defined (_X360))
  750. __asm
  751. {
  752. mov eax,comperand
  753. mov ecx,pDest
  754. mov edx,value
  755. lock cmpxchg [ecx],edx
  756. mov eax,0
  757. setz al
  758. }
  759. #else
  760. return ( InterlockedCompareExchange( TO_INTERLOCK_PARAM(pDest), value, comperand ) == comperand );
  761. #endif
  762. }
  763. #endif
  764. #if !defined( USE_INTRINSIC_INTERLOCKED ) || defined( _WIN64 )
  765. void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value )
  766. {
  767. Assert( (size_t)pDest % 4 == 0 );
  768. return InterlockedExchangePointer( TO_INTERLOCK_PARAM(pDest), value );
  769. }
  770. void *ThreadInterlockedCompareExchangePointer( void * volatile *pDest, void *value, void *comperand )
  771. {
  772. Assert( (size_t)pDest % 4 == 0 );
  773. return InterlockedCompareExchangePointer( TO_INTERLOCK_PTR_PARAM(pDest), value, comperand );
  774. }
  775. bool ThreadInterlockedAssignPointerIf( void * volatile *pDest, void *value, void *comperand )
  776. {
  777. Assert( (size_t)pDest % 4 == 0 );
  778. #if !(defined(_WIN64) || defined (_X360))
  779. __asm
  780. {
  781. mov eax,comperand
  782. mov ecx,pDest
  783. mov edx,value
  784. lock cmpxchg [ecx],edx
  785. mov eax,0
  786. setz al
  787. }
  788. #else
  789. return ( InterlockedCompareExchangePointer( TO_INTERLOCK_PTR_PARAM(pDest), value, comperand ) == comperand );
  790. #endif
  791. }
  792. #endif
  793. int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand )
  794. {
  795. Assert( (size_t)pDest % 8 == 0 );
  796. #if defined(_WIN64) || defined (_X360)
  797. return InterlockedCompareExchange64( pDest, value, comperand );
  798. #else
  799. __asm
  800. {
  801. lea esi,comperand;
  802. lea edi,value;
  803. mov eax,[esi];
  804. mov edx,4[esi];
  805. mov ebx,[edi];
  806. mov ecx,4[edi];
  807. mov esi,pDest;
  808. lock CMPXCHG8B [esi];
  809. }
  810. #endif
  811. }
  812. bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand )
  813. {
  814. Assert( (size_t)pDest % 8 == 0 );
  815. #if defined(PLATFORM_WINDOWS_PC32 )
  816. __asm
  817. {
  818. lea esi,comperand;
  819. lea edi,value;
  820. mov eax,[esi];
  821. mov edx,4[esi];
  822. mov ebx,[edi];
  823. mov ecx,4[edi];
  824. mov esi,pDest;
  825. lock CMPXCHG8B [esi];
  826. mov eax,0;
  827. setz al;
  828. }
  829. #else
  830. return ( ThreadInterlockedCompareExchange64( pDest, value, comperand ) == comperand );
  831. #endif
  832. }
  833. #if defined( PLATFORM_64BITS )
  834. #if _MSC_VER < 1500
  835. // This intrinsic isn't supported on VS2005.
  836. extern "C" unsigned char _InterlockedCompareExchange128( int64 volatile * Destination, int64 ExchangeHigh, int64 ExchangeLow, int64 * ComparandResult );
  837. #endif
  838. bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand )
  839. {
  840. Assert( ( (size_t)pDest % 16 ) == 0 );
  841. volatile int64 *pDest64 = ( volatile int64 * )pDest;
  842. int64 *pValue64 = ( int64 * )&value;
  843. int64 *pComperand64 = ( int64 * )&comperand;
  844. // Description:
  845. // The CMPXCHG16B instruction compares the 128-bit value in the RDX:RAX and RCX:RBX registers
  846. // with a 128-bit memory location. If the values are equal, the zero flag (ZF) is set,
  847. // and the RCX:RBX value is copied to the memory location.
  848. // Otherwise, the ZF flag is cleared, and the memory value is copied to RDX:RAX.
  849. // _InterlockedCompareExchange128: http://msdn.microsoft.com/en-us/library/bb514094.aspx
  850. return _InterlockedCompareExchange128( pDest64, pValue64[1], pValue64[0], pComperand64 ) == 1;
  851. }
  852. #endif // PLATFORM_64BITS
  853. int64 ThreadInterlockedIncrement64( int64 volatile *pDest )
  854. {
  855. Assert( (size_t)pDest % 8 == 0 );
  856. int64 Old;
  857. do
  858. {
  859. Old = *pDest;
  860. } while (ThreadInterlockedCompareExchange64(pDest, Old + 1, Old) != Old);
  861. return Old + 1;
  862. }
  863. int64 ThreadInterlockedDecrement64( int64 volatile *pDest )
  864. {
  865. Assert( (size_t)pDest % 8 == 0 );
  866. int64 Old;
  867. do
  868. {
  869. Old = *pDest;
  870. } while (ThreadInterlockedCompareExchange64(pDest, Old - 1, Old) != Old);
  871. return Old - 1;
  872. }
  873. int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value )
  874. {
  875. Assert( (size_t)pDest % 8 == 0 );
  876. int64 Old;
  877. do
  878. {
  879. Old = *pDest;
  880. } while (ThreadInterlockedCompareExchange64(pDest, value, Old) != Old);
  881. return Old;
  882. }
  883. int64 ThreadInterlockedExchangeAdd64( int64 volatile *pDest, int64 value )
  884. {
  885. Assert( (size_t)pDest % 8 == 0 );
  886. int64 Old;
  887. do
  888. {
  889. Old = *pDest;
  890. } while (ThreadInterlockedCompareExchange64(pDest, Old + value, Old) != Old);
  891. return Old;
  892. }
  893. #elif defined(GNUC)
  894. #ifdef OSX
  895. #include <libkern/OSAtomic.h>
  896. #endif
  897. long ThreadInterlockedIncrement( long volatile *pDest )
  898. {
  899. return __sync_fetch_and_add( pDest, 1 ) + 1;
  900. }
  901. long ThreadInterlockedDecrement( long volatile *pDest )
  902. {
  903. return __sync_fetch_and_sub( pDest, 1 ) - 1;
  904. }
  905. long ThreadInterlockedExchange( long volatile *pDest, long value )
  906. {
  907. return __sync_lock_test_and_set( pDest, value );
  908. }
  909. long ThreadInterlockedExchangeAdd( long volatile *pDest, long value )
  910. {
  911. return __sync_fetch_and_add( pDest, value );
  912. }
  913. long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand )
  914. {
  915. return __sync_val_compare_and_swap( pDest, comperand, value );
  916. }
  917. bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand )
  918. {
  919. return __sync_bool_compare_and_swap( pDest, comperand, value );
  920. }
  921. void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value )
  922. {
  923. return __sync_lock_test_and_set( pDest, value );
  924. }
  925. void *ThreadInterlockedCompareExchangePointer( void *volatile *pDest, void *value, void *comperand )
  926. {
  927. return __sync_val_compare_and_swap( pDest, comperand, value );
  928. }
  929. bool ThreadInterlockedAssignPointerIf( void * volatile *pDest, void *value, void *comperand )
  930. {
  931. return __sync_bool_compare_and_swap( pDest, comperand, value );
  932. }
  933. int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand )
  934. {
  935. #if defined(OSX)
  936. int64 retVal = *pDest;
  937. if ( OSAtomicCompareAndSwap64( comperand, value, pDest ) )
  938. retVal = *pDest;
  939. return retVal;
  940. #else
  941. return __sync_val_compare_and_swap( pDest, comperand, value );
  942. #endif
  943. }
  944. bool ThreadInterlockedAssignIf64( int64 volatile * pDest, int64 value, int64 comperand )
  945. {
  946. return __sync_bool_compare_and_swap( pDest, comperand, value );
  947. }
  948. int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value )
  949. {
  950. Assert( (size_t)pDest % 8 == 0 );
  951. int64 Old;
  952. do
  953. {
  954. Old = *pDest;
  955. } while (ThreadInterlockedCompareExchange64(pDest, value, Old) != Old);
  956. return Old;
  957. }
  958. #else
  959. // This will perform horribly,
  960. #error "Falling back to mutexed interlocked operations, you really don't have intrinsics you can use?"ß
  961. CThreadMutex g_InterlockedMutex;
  962. long ThreadInterlockedIncrement( long volatile *pDest )
  963. {
  964. AUTO_LOCK( g_InterlockedMutex );
  965. return ++(*pDest);
  966. }
  967. long ThreadInterlockedDecrement( long volatile *pDest )
  968. {
  969. AUTO_LOCK( g_InterlockedMutex );
  970. return --(*pDest);
  971. }
  972. long ThreadInterlockedExchange( long volatile *pDest, long value )
  973. {
  974. AUTO_LOCK( g_InterlockedMutex );
  975. long retVal = *pDest;
  976. *pDest = value;
  977. return retVal;
  978. }
  979. void *ThreadInterlockedExchangePointer( void * volatile *pDest, void *value )
  980. {
  981. AUTO_LOCK( g_InterlockedMutex );
  982. void *retVal = *pDest;
  983. *pDest = value;
  984. return retVal;
  985. }
  986. long ThreadInterlockedExchangeAdd( long volatile *pDest, long value )
  987. {
  988. AUTO_LOCK( g_InterlockedMutex );
  989. long retVal = *pDest;
  990. *pDest += value;
  991. return retVal;
  992. }
  993. long ThreadInterlockedCompareExchange( long volatile *pDest, long value, long comperand )
  994. {
  995. AUTO_LOCK( g_InterlockedMutex );
  996. long retVal = *pDest;
  997. if ( *pDest == comperand )
  998. *pDest = value;
  999. return retVal;
  1000. }
  1001. void *ThreadInterlockedCompareExchangePointer( void * volatile *pDest, void *value, void *comperand )
  1002. {
  1003. AUTO_LOCK( g_InterlockedMutex );
  1004. void *retVal = *pDest;
  1005. if ( *pDest == comperand )
  1006. *pDest = value;
  1007. return retVal;
  1008. }
  1009. int64 ThreadInterlockedCompareExchange64( int64 volatile *pDest, int64 value, int64 comperand )
  1010. {
  1011. Assert( (size_t)pDest % 8 == 0 );
  1012. AUTO_LOCK( g_InterlockedMutex );
  1013. int64 retVal = *pDest;
  1014. if ( *pDest == comperand )
  1015. *pDest = value;
  1016. return retVal;
  1017. }
  1018. int64 ThreadInterlockedExchange64( int64 volatile *pDest, int64 value )
  1019. {
  1020. Assert( (size_t)pDest % 8 == 0 );
  1021. int64 Old;
  1022. do
  1023. {
  1024. Old = *pDest;
  1025. } while (ThreadInterlockedCompareExchange64(pDest, value, Old) != Old);
  1026. return Old;
  1027. }
  1028. bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand )
  1029. {
  1030. Assert( (size_t)pDest % 8 == 0 );
  1031. return ( ThreadInterlockedCompareExchange64( pDest, value, comperand ) == comperand );
  1032. }
  1033. bool ThreadInterlockedAssignIf( long volatile *pDest, long value, long comperand )
  1034. {
  1035. Assert( (size_t)pDest % 4 == 0 );
  1036. return ( ThreadInterlockedCompareExchange( pDest, value, comperand ) == comperand );
  1037. }
  1038. #endif
  1039. //-----------------------------------------------------------------------------
  1040. #if defined(_WIN32) && defined(THREAD_PROFILER)
  1041. void ThreadNotifySyncNoop(void *p) {}
  1042. #define MAP_THREAD_PROFILER_CALL( from, to ) \
  1043. void from(void *p) \
  1044. { \
  1045. static CDynamicFunction<void (*)(void *)> dynFunc( "libittnotify.dll", #to, ThreadNotifySyncNoop ); \
  1046. (*dynFunc)(p); \
  1047. }
  1048. MAP_THREAD_PROFILER_CALL( ThreadNotifySyncPrepare, __itt_notify_sync_prepare );
  1049. MAP_THREAD_PROFILER_CALL( ThreadNotifySyncCancel, __itt_notify_sync_cancel );
  1050. MAP_THREAD_PROFILER_CALL( ThreadNotifySyncAcquired, __itt_notify_sync_acquired );
  1051. MAP_THREAD_PROFILER_CALL( ThreadNotifySyncReleasing, __itt_notify_sync_releasing );
  1052. #endif
  1053. //-----------------------------------------------------------------------------
  1054. //
  1055. // CThreadMutex
  1056. //
  1057. //-----------------------------------------------------------------------------
  1058. #ifndef POSIX
  1059. CThreadMutex::CThreadMutex()
  1060. {
  1061. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1062. memset( &m_CriticalSection, 0, sizeof(m_CriticalSection) );
  1063. #endif
  1064. InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *)&m_CriticalSection, 4000);
  1065. #ifdef THREAD_MUTEX_TRACING_SUPPORTED
  1066. // These need to be initialized unconditionally in case mixing release & debug object modules
  1067. // Lock and unlock may be emitted as COMDATs, in which case may get spurious output
  1068. m_currentOwnerID = m_lockCount = 0;
  1069. m_bTrace = false;
  1070. #endif
  1071. }
  1072. CThreadMutex::~CThreadMutex()
  1073. {
  1074. DeleteCriticalSection((CRITICAL_SECTION *)&m_CriticalSection);
  1075. }
  1076. #endif // !POSIX
  1077. #if defined( _WIN32 ) && !defined( _X360 )
  1078. typedef BOOL (WINAPI*TryEnterCriticalSectionFunc_t)(LPCRITICAL_SECTION);
  1079. static CDynamicFunction<TryEnterCriticalSectionFunc_t> DynTryEnterCriticalSection( "Kernel32.dll", "TryEnterCriticalSection" );
  1080. #elif defined( _X360 )
  1081. #define DynTryEnterCriticalSection TryEnterCriticalSection
  1082. #endif
  1083. bool CThreadMutex::TryLock()
  1084. {
  1085. #if defined( _WIN32 )
  1086. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1087. uint thisThreadID = ThreadGetCurrentId();
  1088. if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) )
  1089. Msg( "Thread %u about to try-wait for lock %p owned by %u\n", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
  1090. #endif
  1091. if ( DynTryEnterCriticalSection != NULL )
  1092. {
  1093. if ( (*DynTryEnterCriticalSection )( (CRITICAL_SECTION *)&m_CriticalSection ) != FALSE )
  1094. {
  1095. #ifdef THREAD_MUTEX_TRACING_ENABLED
  1096. if (m_lockCount == 0)
  1097. {
  1098. // we now own it for the first time. Set owner information
  1099. m_currentOwnerID = thisThreadID;
  1100. if ( m_bTrace )
  1101. Msg( "Thread %u now owns lock 0x%p\n", m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
  1102. }
  1103. m_lockCount++;
  1104. #endif
  1105. return true;
  1106. }
  1107. return false;
  1108. }
  1109. Lock();
  1110. return true;
  1111. #elif defined( POSIX )
  1112. return pthread_mutex_trylock( &m_Mutex ) == 0;
  1113. #else
  1114. #error "Implement me!"
  1115. return true;
  1116. #endif
  1117. }
  1118. //-----------------------------------------------------------------------------
  1119. //
  1120. // CThreadFastMutex
  1121. //
  1122. //-----------------------------------------------------------------------------
  1123. #define THREAD_SPIN (8*1024)
  1124. void CThreadFastMutex::Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile
  1125. {
  1126. int i;
  1127. if ( nSpinSleepTime != TT_INFINITE )
  1128. {
  1129. for ( i = THREAD_SPIN; i != 0; --i )
  1130. {
  1131. if ( TryLock( threadId ) )
  1132. {
  1133. return;
  1134. }
  1135. ThreadPause();
  1136. }
  1137. for ( i = THREAD_SPIN; i != 0; --i )
  1138. {
  1139. if ( TryLock( threadId ) )
  1140. {
  1141. return;
  1142. }
  1143. ThreadPause();
  1144. if ( i % 1024 == 0 )
  1145. {
  1146. ThreadSleep( 0 );
  1147. }
  1148. }
  1149. #ifdef _WIN32
  1150. if ( !nSpinSleepTime && GetThreadPriority( GetCurrentThread() ) > THREAD_PRIORITY_NORMAL )
  1151. {
  1152. nSpinSleepTime = 1;
  1153. }
  1154. else
  1155. #endif
  1156. if ( nSpinSleepTime )
  1157. {
  1158. for ( i = THREAD_SPIN; i != 0; --i )
  1159. {
  1160. if ( TryLock( threadId ) )
  1161. {
  1162. return;
  1163. }
  1164. ThreadPause();
  1165. ThreadSleep( 0 );
  1166. }
  1167. }
  1168. for ( ;; ) // coded as for instead of while to make easy to breakpoint success
  1169. {
  1170. if ( TryLock( threadId ) )
  1171. {
  1172. return;
  1173. }
  1174. ThreadPause();
  1175. ThreadSleep( nSpinSleepTime );
  1176. }
  1177. }
  1178. else
  1179. {
  1180. for ( ;; ) // coded as for instead of while to make easy to breakpoint success
  1181. {
  1182. if ( TryLock( threadId ) )
  1183. {
  1184. return;
  1185. }
  1186. ThreadPause();
  1187. }
  1188. }
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. //
  1192. // CThreadRWLock
  1193. //
  1194. //-----------------------------------------------------------------------------
  1195. void CThreadRWLock::WaitForRead()
  1196. {
  1197. m_nPendingReaders++;
  1198. do
  1199. {
  1200. m_mutex.Unlock();
  1201. m_CanRead.Wait();
  1202. m_mutex.Lock();
  1203. }
  1204. while (m_nWriters);
  1205. m_nPendingReaders--;
  1206. }
  1207. void CThreadRWLock::LockForWrite()
  1208. {
  1209. m_mutex.Lock();
  1210. bool bWait = ( m_nWriters != 0 || m_nActiveReaders != 0 );
  1211. m_nWriters++;
  1212. m_CanRead.Reset();
  1213. m_mutex.Unlock();
  1214. if ( bWait )
  1215. {
  1216. m_CanWrite.Wait();
  1217. }
  1218. }
  1219. void CThreadRWLock::UnlockWrite()
  1220. {
  1221. m_mutex.Lock();
  1222. m_nWriters--;
  1223. if ( m_nWriters == 0)
  1224. {
  1225. if ( m_nPendingReaders )
  1226. {
  1227. m_CanRead.Set();
  1228. }
  1229. }
  1230. else
  1231. {
  1232. m_CanWrite.Set();
  1233. }
  1234. m_mutex.Unlock();
  1235. }
  1236. //-----------------------------------------------------------------------------
  1237. //
  1238. // CThreadSpinRWLock
  1239. //
  1240. //-----------------------------------------------------------------------------
  1241. void CThreadSpinRWLock::SpinLockForWrite( const uint32 threadId )
  1242. {
  1243. int i;
  1244. for ( i = 1000; i != 0; --i )
  1245. {
  1246. if ( TryLockForWrite( threadId ) )
  1247. {
  1248. return;
  1249. }
  1250. ThreadPause();
  1251. }
  1252. for ( i = 20000; i != 0; --i )
  1253. {
  1254. if ( TryLockForWrite( threadId ) )
  1255. {
  1256. return;
  1257. }
  1258. ThreadPause();
  1259. ThreadSleep( 0 );
  1260. }
  1261. for ( ;; ) // coded as for instead of while to make easy to breakpoint success
  1262. {
  1263. if ( TryLockForWrite( threadId ) )
  1264. {
  1265. return;
  1266. }
  1267. ThreadPause();
  1268. ThreadSleep( 1 );
  1269. }
  1270. }
  1271. void CThreadSpinRWLock::LockForRead()
  1272. {
  1273. int i;
  1274. // In order to grab a read lock, the number of readers must not change and no thread can own the write lock
  1275. LockInfo_t oldValue;
  1276. LockInfo_t newValue;
  1277. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1278. oldValue.m_writerId = 0;
  1279. newValue.m_nReaders = oldValue.m_nReaders + 1;
  1280. newValue.m_writerId = 0;
  1281. if( m_nWriters == 0 && AssignIf( newValue, oldValue ) )
  1282. return;
  1283. ThreadPause();
  1284. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1285. newValue.m_nReaders = oldValue.m_nReaders + 1;
  1286. for ( i = 1000; i != 0; --i )
  1287. {
  1288. if( m_nWriters == 0 && AssignIf( newValue, oldValue ) )
  1289. return;
  1290. ThreadPause();
  1291. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1292. newValue.m_nReaders = oldValue.m_nReaders + 1;
  1293. }
  1294. for ( i = 20000; i != 0; --i )
  1295. {
  1296. if( m_nWriters == 0 && AssignIf( newValue, oldValue ) )
  1297. return;
  1298. ThreadPause();
  1299. ThreadSleep( 0 );
  1300. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1301. newValue.m_nReaders = oldValue.m_nReaders + 1;
  1302. }
  1303. for ( ;; ) // coded as for instead of while to make easy to breakpoint success
  1304. {
  1305. if( m_nWriters == 0 && AssignIf( newValue, oldValue ) )
  1306. return;
  1307. ThreadPause();
  1308. ThreadSleep( 1 );
  1309. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1310. newValue.m_nReaders = oldValue.m_nReaders + 1;
  1311. }
  1312. }
  1313. void CThreadSpinRWLock::UnlockRead()
  1314. {
  1315. int i;
  1316. Assert( m_lockInfo.m_nReaders > 0 && m_lockInfo.m_writerId == 0 );
  1317. LockInfo_t oldValue;
  1318. LockInfo_t newValue;
  1319. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1320. oldValue.m_writerId = 0;
  1321. newValue.m_nReaders = oldValue.m_nReaders - 1;
  1322. newValue.m_writerId = 0;
  1323. if( AssignIf( newValue, oldValue ) )
  1324. return;
  1325. ThreadPause();
  1326. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1327. newValue.m_nReaders = oldValue.m_nReaders - 1;
  1328. for ( i = 500; i != 0; --i )
  1329. {
  1330. if( AssignIf( newValue, oldValue ) )
  1331. return;
  1332. ThreadPause();
  1333. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1334. newValue.m_nReaders = oldValue.m_nReaders - 1;
  1335. }
  1336. for ( i = 20000; i != 0; --i )
  1337. {
  1338. if( AssignIf( newValue, oldValue ) )
  1339. return;
  1340. ThreadPause();
  1341. ThreadSleep( 0 );
  1342. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1343. newValue.m_nReaders = oldValue.m_nReaders - 1;
  1344. }
  1345. for ( ;; ) // coded as for instead of while to make easy to breakpoint success
  1346. {
  1347. if( AssignIf( newValue, oldValue ) )
  1348. return;
  1349. ThreadPause();
  1350. ThreadSleep( 1 );
  1351. oldValue.m_nReaders = m_lockInfo.m_nReaders;
  1352. newValue.m_nReaders = oldValue.m_nReaders - 1;
  1353. }
  1354. }
  1355. void CThreadSpinRWLock::UnlockWrite()
  1356. {
  1357. Assert( m_lockInfo.m_writerId == ThreadGetCurrentId() && m_lockInfo.m_nReaders == 0 );
  1358. static const LockInfo_t newValue = { 0, 0 };
  1359. #if defined(_X360)
  1360. // X360TBD: Serious Perf implications, not yet. __sync();
  1361. #endif
  1362. ThreadInterlockedExchange64( (int64 *)&m_lockInfo, *((int64 *)&newValue) );
  1363. m_nWriters--;
  1364. }
  1365. //-----------------------------------------------------------------------------
  1366. //
  1367. // CThread
  1368. //
  1369. //-----------------------------------------------------------------------------
  1370. CThreadLocalPtr<CThread> g_pCurThread;
  1371. //---------------------------------------------------------
  1372. CThread::CThread()
  1373. :
  1374. #ifdef _WIN32
  1375. m_hThread( NULL ),
  1376. #endif
  1377. m_threadId( 0 ),
  1378. m_result( 0 ),
  1379. m_flags( 0 )
  1380. {
  1381. m_szName[0] = 0;
  1382. }
  1383. //---------------------------------------------------------
  1384. CThread::~CThread()
  1385. {
  1386. #ifdef _WIN32
  1387. if (m_hThread)
  1388. #elif defined(POSIX)
  1389. if ( m_threadId )
  1390. #endif
  1391. {
  1392. if ( IsAlive() )
  1393. {
  1394. Msg( "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" );
  1395. #ifdef _WIN32
  1396. DoNewAssertDialog( __FILE__, __LINE__, "Illegal termination of worker thread! Threads must negotiate an end to the thread before the CThread object is destroyed.\n" );
  1397. #endif
  1398. if ( GetCurrentCThread() == this )
  1399. {
  1400. Stop(); // BUGBUG: Alfred - this doesn't make sense, this destructor fires from the hosting thread not the thread itself!!
  1401. }
  1402. }
  1403. #ifdef _WIN32
  1404. // Now that the worker thread has exited (which we know because we presumably waited
  1405. // on the thread handle for it to exit) we can finally close the thread handle. We
  1406. // cannot do this any earlier, and certainly not in CThread::ThreadProc().
  1407. CloseHandle( m_hThread );
  1408. #endif
  1409. }
  1410. }
  1411. //---------------------------------------------------------
  1412. const char *CThread::GetName()
  1413. {
  1414. AUTO_LOCK( m_Lock );
  1415. if ( !m_szName[0] )
  1416. {
  1417. #ifdef _WIN32
  1418. _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(%p/%p)", this, m_hThread );
  1419. #elif defined(POSIX)
  1420. _snprintf( m_szName, sizeof(m_szName) - 1, "Thread(0x%x/0x%x)", (uint)this, (uint)m_threadId );
  1421. #endif
  1422. m_szName[sizeof(m_szName) - 1] = 0;
  1423. }
  1424. return m_szName;
  1425. }
  1426. //---------------------------------------------------------
  1427. void CThread::SetName(const char *pszName)
  1428. {
  1429. AUTO_LOCK( m_Lock );
  1430. strncpy( m_szName, pszName, sizeof(m_szName) - 1 );
  1431. m_szName[sizeof(m_szName) - 1] = 0;
  1432. }
  1433. //---------------------------------------------------------
  1434. bool CThread::Start( unsigned nBytesStack )
  1435. {
  1436. AUTO_LOCK( m_Lock );
  1437. if ( IsAlive() )
  1438. {
  1439. AssertMsg( 0, "Tried to create a thread that has already been created!" );
  1440. return false;
  1441. }
  1442. bool bInitSuccess = false;
  1443. CThreadEvent createComplete;
  1444. ThreadInit_t init = { this, &createComplete, &bInitSuccess };
  1445. #ifdef _WIN32
  1446. HANDLE hThread;
  1447. m_hThread = hThread = (HANDLE)VCRHook_CreateThread( NULL,
  1448. nBytesStack,
  1449. (LPTHREAD_START_ROUTINE)GetThreadProc(),
  1450. new ThreadInit_t(init),
  1451. CREATE_SUSPENDED,
  1452. &m_threadId );
  1453. if ( !hThread )
  1454. {
  1455. AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() );
  1456. return false;
  1457. }
  1458. Plat_ApplyHardwareDataBreakpointsToNewThread( m_threadId );
  1459. ResumeThread( hThread );
  1460. #elif defined(POSIX)
  1461. pthread_attr_t attr;
  1462. pthread_attr_init( &attr );
  1463. // From http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_attr_setstacksize.3.html
  1464. // A thread's stack size is fixed at the time of thread creation. Only the main thread can dynamically grow its stack.
  1465. pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) );
  1466. if ( pthread_create( &m_threadId, &attr, (void *(*)(void *))GetThreadProc(), new ThreadInit_t( init ) ) != 0 )
  1467. {
  1468. AssertMsg1( 0, "Failed to create thread (error 0x%x)", GetLastError() );
  1469. return false;
  1470. }
  1471. Plat_ApplyHardwareDataBreakpointsToNewThread( (long unsigned int)m_threadId );
  1472. bInitSuccess = true;
  1473. #endif
  1474. #if !defined( OSX )
  1475. ThreadSetDebugName( m_threadId, m_szName );
  1476. #endif
  1477. if ( !WaitForCreateComplete( &createComplete ) )
  1478. {
  1479. Msg( "Thread failed to initialize\n" );
  1480. #ifdef _WIN32
  1481. CloseHandle( m_hThread );
  1482. m_hThread = NULL;
  1483. m_threadId = 0;
  1484. #elif defined(POSIX)
  1485. m_threadId = 0;
  1486. #endif
  1487. return false;
  1488. }
  1489. if ( !bInitSuccess )
  1490. {
  1491. Msg( "Thread failed to initialize\n" );
  1492. #ifdef _WIN32
  1493. CloseHandle( m_hThread );
  1494. m_hThread = NULL;
  1495. m_threadId = 0;
  1496. #elif defined(POSIX)
  1497. m_threadId = 0;
  1498. #endif
  1499. return false;
  1500. }
  1501. #ifdef _WIN32
  1502. if ( !m_hThread )
  1503. {
  1504. Msg( "Thread exited immediately\n" );
  1505. }
  1506. #endif
  1507. #ifdef _WIN32
  1508. return !!m_hThread;
  1509. #elif defined(POSIX)
  1510. return !!m_threadId;
  1511. #endif
  1512. }
  1513. //---------------------------------------------------------
  1514. //
  1515. // Return true if the thread exists. false otherwise
  1516. //
  1517. bool CThread::IsAlive()
  1518. {
  1519. #ifdef _WIN32
  1520. DWORD dwExitCode;
  1521. return ( m_hThread &&
  1522. GetExitCodeThread( m_hThread, &dwExitCode ) &&
  1523. dwExitCode == STILL_ACTIVE );
  1524. #elif defined(POSIX)
  1525. return m_threadId;
  1526. #endif
  1527. }
  1528. //---------------------------------------------------------
  1529. bool CThread::Join(unsigned timeout)
  1530. {
  1531. #ifdef _WIN32
  1532. if ( m_hThread )
  1533. #elif defined(POSIX)
  1534. if ( m_threadId )
  1535. #endif
  1536. {
  1537. AssertMsg(GetCurrentCThread() != this, _T("Thread cannot be joined with self"));
  1538. #ifdef _WIN32
  1539. return ThreadJoin( (ThreadHandle_t)m_hThread );
  1540. #elif defined(POSIX)
  1541. return ThreadJoin( (ThreadHandle_t)m_threadId );
  1542. #endif
  1543. }
  1544. return true;
  1545. }
  1546. //---------------------------------------------------------
  1547. #ifdef _WIN32
  1548. HANDLE CThread::GetThreadHandle()
  1549. {
  1550. return m_hThread;
  1551. }
  1552. #endif
  1553. #if defined( _WIN32 ) || defined( LINUX )
  1554. //---------------------------------------------------------
  1555. uint CThread::GetThreadId()
  1556. {
  1557. return m_threadId;
  1558. }
  1559. #endif
  1560. //---------------------------------------------------------
  1561. int CThread::GetResult()
  1562. {
  1563. return m_result;
  1564. }
  1565. //---------------------------------------------------------
  1566. //
  1567. // Forcibly, abnormally, but relatively cleanly stop the thread
  1568. //
  1569. void CThread::Stop(int exitCode)
  1570. {
  1571. if ( !IsAlive() )
  1572. return;
  1573. if ( GetCurrentCThread() == this )
  1574. {
  1575. m_result = exitCode;
  1576. if ( !( m_flags & SUPPORT_STOP_PROTOCOL ) )
  1577. {
  1578. OnExit();
  1579. g_pCurThread = (int)NULL;
  1580. #ifdef _WIN32
  1581. CloseHandle( m_hThread );
  1582. m_hThread = NULL;
  1583. #endif
  1584. Cleanup();
  1585. }
  1586. throw exitCode;
  1587. }
  1588. else
  1589. AssertMsg( 0, "Only thread can stop self: Use a higher-level protocol");
  1590. }
  1591. //---------------------------------------------------------
  1592. int CThread::GetPriority() const
  1593. {
  1594. #ifdef _WIN32
  1595. return GetThreadPriority(m_hThread);
  1596. #elif defined(POSIX)
  1597. struct sched_param thread_param;
  1598. int policy;
  1599. pthread_getschedparam( m_threadId, &policy, &thread_param );
  1600. return thread_param.sched_priority;
  1601. #endif
  1602. }
  1603. //---------------------------------------------------------
  1604. bool CThread::SetPriority(int priority)
  1605. {
  1606. #ifdef _WIN32
  1607. return ThreadSetPriority( (ThreadHandle_t)m_hThread, priority );
  1608. #else
  1609. return ThreadSetPriority( (ThreadHandle_t)m_threadId, priority );
  1610. #endif
  1611. }
  1612. //---------------------------------------------------------
  1613. void CThread::SuspendCooperative()
  1614. {
  1615. if ( ThreadGetCurrentId() == (ThreadId_t)m_threadId )
  1616. {
  1617. m_SuspendEventSignal.Set();
  1618. m_nSuspendCount = 1;
  1619. m_SuspendEvent.Wait();
  1620. m_nSuspendCount = 0;
  1621. }
  1622. else
  1623. {
  1624. Assert( !"Suspend not called from worker thread, this would be a bug" );
  1625. }
  1626. }
  1627. //---------------------------------------------------------
  1628. void CThread::ResumeCooperative()
  1629. {
  1630. Assert( m_nSuspendCount == 1 );
  1631. m_SuspendEvent.Set();
  1632. }
  1633. void CThread::BWaitForThreadSuspendCooperative()
  1634. {
  1635. m_SuspendEventSignal.Wait();
  1636. }
  1637. #ifndef LINUX
  1638. //---------------------------------------------------------
  1639. unsigned int CThread::Suspend()
  1640. {
  1641. #ifdef _WIN32
  1642. return ( SuspendThread(m_hThread) != 0 );
  1643. #elif defined(OSX)
  1644. int susCount = m_nSuspendCount++;
  1645. while ( thread_suspend( pthread_mach_thread_np(m_threadId) ) != KERN_SUCCESS )
  1646. {
  1647. };
  1648. return ( susCount) != 0;
  1649. #else
  1650. #error
  1651. #endif
  1652. }
  1653. //---------------------------------------------------------
  1654. unsigned int CThread::Resume()
  1655. {
  1656. #ifdef _WIN32
  1657. return ( ResumeThread(m_hThread) != 0 );
  1658. #elif defined(OSX)
  1659. int susCount = m_nSuspendCount++;
  1660. while ( thread_resume( pthread_mach_thread_np(m_threadId) ) != KERN_SUCCESS )
  1661. {
  1662. };
  1663. return ( susCount - 1) != 0;
  1664. #else
  1665. #error
  1666. #endif
  1667. }
  1668. #endif
  1669. //---------------------------------------------------------
  1670. bool CThread::Terminate(int exitCode)
  1671. {
  1672. #ifndef _X360
  1673. #ifdef _WIN32
  1674. // I hope you know what you're doing!
  1675. if (!TerminateThread(m_hThread, exitCode))
  1676. return false;
  1677. CloseHandle( m_hThread );
  1678. m_hThread = NULL;
  1679. Cleanup();
  1680. #elif defined(POSIX)
  1681. pthread_kill( m_threadId, SIGKILL );
  1682. Cleanup();
  1683. #endif
  1684. return true;
  1685. #else
  1686. AssertMsg( 0, "Cannot terminate a thread on the Xbox!" );
  1687. return false;
  1688. #endif
  1689. }
  1690. //---------------------------------------------------------
  1691. //
  1692. // Get the Thread object that represents the current thread, if any.
  1693. // Can return NULL if the current thread was not created using
  1694. // CThread
  1695. //
  1696. CThread *CThread::GetCurrentCThread()
  1697. {
  1698. return g_pCurThread;
  1699. }
  1700. //---------------------------------------------------------
  1701. //
  1702. // Offer a context switch. Under Win32, equivalent to Sleep(0)
  1703. //
  1704. void CThread::Yield()
  1705. {
  1706. #ifdef _WIN32
  1707. ::Sleep(0);
  1708. #elif defined(POSIX)
  1709. pthread_yield();
  1710. #endif
  1711. }
  1712. //---------------------------------------------------------
  1713. //
  1714. // This method causes the current thread to yield and not to be
  1715. // scheduled for further execution until a certain amount of real
  1716. // time has elapsed, more or less.
  1717. //
  1718. void CThread::Sleep(unsigned duration)
  1719. {
  1720. #ifdef _WIN32
  1721. ::Sleep(duration);
  1722. #elif defined(POSIX)
  1723. usleep( duration * 1000 );
  1724. #endif
  1725. }
  1726. //---------------------------------------------------------
  1727. bool CThread::Init()
  1728. {
  1729. return true;
  1730. }
  1731. //---------------------------------------------------------
  1732. void CThread::OnExit()
  1733. {
  1734. }
  1735. //---------------------------------------------------------
  1736. void CThread::Cleanup()
  1737. {
  1738. m_threadId = 0;
  1739. }
  1740. //---------------------------------------------------------
  1741. bool CThread::WaitForCreateComplete(CThreadEvent * pEvent)
  1742. {
  1743. // Force serialized thread creation...
  1744. if (!pEvent->Wait(60000))
  1745. {
  1746. AssertMsg( 0, "Probably deadlock or failure waiting for thread to initialize." );
  1747. return false;
  1748. }
  1749. return true;
  1750. }
  1751. //---------------------------------------------------------
  1752. bool CThread::IsThreadRunning()
  1753. {
  1754. #ifdef _PS3
  1755. // ThreadIsThreadIdRunning() doesn't work on PS3 if the thread is in a zombie state
  1756. return m_eventTheadExit.Check();
  1757. #else
  1758. return ThreadIsThreadIdRunning( (ThreadId_t)m_threadId );
  1759. #endif
  1760. }
  1761. //---------------------------------------------------------
  1762. CThread::ThreadProc_t CThread::GetThreadProc()
  1763. {
  1764. return ThreadProc;
  1765. }
  1766. //---------------------------------------------------------
  1767. unsigned __stdcall CThread::ThreadProc(LPVOID pv)
  1768. {
  1769. std::auto_ptr<ThreadInit_t> pInit((ThreadInit_t *)pv);
  1770. #ifdef _X360
  1771. // Make sure all threads are consistent w.r.t floating-point math
  1772. SetupFPUControlWord();
  1773. #endif
  1774. CThread *pThread = pInit->pThread;
  1775. g_pCurThread = pThread;
  1776. g_pCurThread->m_pStackBase = AlignValue( &pThread, 4096 );
  1777. pInit->pThread->m_result = -1;
  1778. bool bInitSuccess = true;
  1779. if ( pInit->pfInitSuccess )
  1780. *(pInit->pfInitSuccess) = false;
  1781. try
  1782. {
  1783. bInitSuccess = pInit->pThread->Init();
  1784. }
  1785. catch (...)
  1786. {
  1787. pInit->pInitCompleteEvent->Set();
  1788. throw;
  1789. }
  1790. if ( pInit->pfInitSuccess )
  1791. *(pInit->pfInitSuccess) = bInitSuccess;
  1792. pInit->pInitCompleteEvent->Set();
  1793. if (!bInitSuccess)
  1794. return 0;
  1795. if ( pInit->pThread->m_flags & SUPPORT_STOP_PROTOCOL )
  1796. {
  1797. try
  1798. {
  1799. pInit->pThread->m_result = pInit->pThread->Run();
  1800. }
  1801. catch (...)
  1802. {
  1803. }
  1804. }
  1805. else
  1806. {
  1807. pInit->pThread->m_result = pInit->pThread->Run();
  1808. }
  1809. pInit->pThread->OnExit();
  1810. g_pCurThread = (int)NULL;
  1811. pInit->pThread->Cleanup();
  1812. return pInit->pThread->m_result;
  1813. }
  1814. //-----------------------------------------------------------------------------
  1815. //
  1816. //-----------------------------------------------------------------------------
  1817. CWorkerThread::CWorkerThread()
  1818. : m_EventSend(true), // must be manual-reset for PeekCall()
  1819. m_EventComplete(true), // must be manual-reset to handle multiple wait with thread properly
  1820. m_Param(0),
  1821. m_pParamFunctor(NULL),
  1822. m_ReturnVal(0)
  1823. {
  1824. }
  1825. //---------------------------------------------------------
  1826. int CWorkerThread::CallWorker(unsigned dw, unsigned timeout, bool fBoostWorkerPriorityToMaster, CFunctor *pParamFunctor)
  1827. {
  1828. return Call(dw, timeout, fBoostWorkerPriorityToMaster, NULL, pParamFunctor);
  1829. }
  1830. //---------------------------------------------------------
  1831. int CWorkerThread::CallMaster(unsigned dw, unsigned timeout)
  1832. {
  1833. return Call(dw, timeout, false);
  1834. }
  1835. //---------------------------------------------------------
  1836. CThreadEvent &CWorkerThread::GetCallHandle()
  1837. {
  1838. return m_EventSend;
  1839. }
  1840. //---------------------------------------------------------
  1841. unsigned CWorkerThread::GetCallParam( CFunctor **ppParamFunctor ) const
  1842. {
  1843. if( ppParamFunctor )
  1844. *ppParamFunctor = m_pParamFunctor;
  1845. return m_Param;
  1846. }
  1847. //---------------------------------------------------------
  1848. int CWorkerThread::BoostPriority()
  1849. {
  1850. int iInitialPriority = GetPriority();
  1851. const int iNewPriority = ThreadGetPriority( (ThreadHandle_t)GetThreadID() );
  1852. if (iNewPriority > iInitialPriority)
  1853. ThreadSetPriority( (ThreadHandle_t)GetThreadID(), iNewPriority);
  1854. return iInitialPriority;
  1855. }
  1856. //---------------------------------------------------------
  1857. static uint32 __stdcall DefaultWaitFunc( int nEvents, CThreadEvent * const *pEvents, int bWaitAll, uint32 timeout )
  1858. {
  1859. return ThreadWaitForEvents( nEvents, pEvents, bWaitAll!=0, timeout );
  1860. // return VCRHook_WaitForMultipleObjects( nHandles, (const void **)pHandles, bWaitAll, timeout );
  1861. }
  1862. int CWorkerThread::Call(unsigned dwParam, unsigned timeout, bool fBoostPriority, WaitFunc_t pfnWait, CFunctor *pParamFunctor)
  1863. {
  1864. AssertMsg(!m_EventSend.Check(), "Cannot perform call if there's an existing call pending" );
  1865. AUTO_LOCK( m_Lock );
  1866. if (!IsAlive())
  1867. return WTCR_FAIL;
  1868. int iInitialPriority = 0;
  1869. if (fBoostPriority)
  1870. {
  1871. iInitialPriority = BoostPriority();
  1872. }
  1873. // set the parameter, signal the worker thread, wait for the completion to be signaled
  1874. m_Param = dwParam;
  1875. m_pParamFunctor = pParamFunctor;
  1876. m_EventComplete.Reset();
  1877. m_EventSend.Set();
  1878. WaitForReply( timeout, pfnWait );
  1879. // MWD: Investigate why setting thread priorities is killing the 360
  1880. #ifndef _X360
  1881. if (fBoostPriority)
  1882. SetPriority(iInitialPriority);
  1883. #endif
  1884. return m_ReturnVal;
  1885. }
  1886. //---------------------------------------------------------
  1887. //
  1888. // Wait for a request from the client
  1889. //
  1890. //---------------------------------------------------------
  1891. int CWorkerThread::WaitForReply( unsigned timeout )
  1892. {
  1893. return WaitForReply( timeout, NULL );
  1894. }
  1895. int CWorkerThread::WaitForReply( unsigned timeout, WaitFunc_t pfnWait )
  1896. {
  1897. if (!pfnWait)
  1898. {
  1899. pfnWait = DefaultWaitFunc;
  1900. }
  1901. #ifdef WIN32
  1902. CThreadEvent threadEvent( GetThreadHandle() );
  1903. #endif
  1904. CThreadEvent *waits[] =
  1905. {
  1906. #ifdef WIN32
  1907. &threadEvent,
  1908. #endif
  1909. &m_EventComplete
  1910. };
  1911. unsigned result;
  1912. bool bInDebugger = Plat_IsInDebugSession();
  1913. do
  1914. {
  1915. #ifdef WIN32
  1916. // Make sure the thread handle hasn't been closed
  1917. if ( !GetThreadHandle() )
  1918. {
  1919. result = WAIT_OBJECT_0 + 1;
  1920. break;
  1921. }
  1922. #endif
  1923. result = (*pfnWait)((sizeof(waits) / sizeof(waits[0])), waits, false,
  1924. (timeout != TT_INFINITE) ? timeout : 30000);
  1925. AssertMsg(timeout != TT_INFINITE || result != WAIT_TIMEOUT, "Possible hung thread, call to thread timed out");
  1926. } while ( bInDebugger && ( timeout == TT_INFINITE && result == WAIT_TIMEOUT ) );
  1927. if ( result != WAIT_OBJECT_0 + 1 )
  1928. {
  1929. if (result == WAIT_TIMEOUT)
  1930. m_ReturnVal = WTCR_TIMEOUT;
  1931. else if (result == WAIT_OBJECT_0)
  1932. {
  1933. DevMsg( 2, "Thread failed to respond, probably exited\n");
  1934. m_EventSend.Reset();
  1935. m_ReturnVal = WTCR_TIMEOUT;
  1936. }
  1937. else
  1938. {
  1939. m_EventSend.Reset();
  1940. m_ReturnVal = WTCR_THREAD_GONE;
  1941. }
  1942. }
  1943. return m_ReturnVal;
  1944. }
  1945. //---------------------------------------------------------
  1946. //
  1947. // Wait for a request from the client
  1948. //
  1949. //---------------------------------------------------------
  1950. bool CWorkerThread::WaitForCall(unsigned * pResult)
  1951. {
  1952. return WaitForCall(TT_INFINITE, pResult);
  1953. }
  1954. //---------------------------------------------------------
  1955. bool CWorkerThread::WaitForCall(unsigned dwTimeout, unsigned * pResult)
  1956. {
  1957. bool returnVal = m_EventSend.Wait(dwTimeout);
  1958. if (pResult)
  1959. *pResult = m_Param;
  1960. return returnVal;
  1961. }
  1962. //---------------------------------------------------------
  1963. //
  1964. // is there a request?
  1965. //
  1966. bool CWorkerThread::PeekCall(unsigned * pParam, CFunctor **ppParamFunctor)
  1967. {
  1968. if (!m_EventSend.Check())
  1969. {
  1970. return false;
  1971. }
  1972. else
  1973. {
  1974. if (pParam)
  1975. {
  1976. *pParam = m_Param;
  1977. }
  1978. if( ppParamFunctor )
  1979. {
  1980. *ppParamFunctor = m_pParamFunctor;
  1981. }
  1982. return true;
  1983. }
  1984. }
  1985. //---------------------------------------------------------
  1986. //
  1987. // Reply to the request
  1988. //
  1989. void CWorkerThread::Reply(unsigned dw)
  1990. {
  1991. m_Param = 0;
  1992. m_ReturnVal = dw;
  1993. // The request is now complete so PeekCall() should fail from
  1994. // now on
  1995. //
  1996. // This event should be reset BEFORE we signal the client
  1997. m_EventSend.Reset();
  1998. // Tell the client we're finished
  1999. m_EventComplete.Set();
  2000. }
  2001. //-----------------------------------------------------------------------------