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.

257 lines
4.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //-----------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #define USED
  14. #include <windows.h>
  15. #include "cmdlib.h"
  16. #define NO_THREAD_NAMES
  17. #include "threads.h"
  18. #include "pacifier.h"
  19. #define MAX_THREADS 16
  20. class CRunThreadsData
  21. {
  22. public:
  23. int m_iThread;
  24. void *m_pUserData;
  25. RunThreadsFn m_Fn;
  26. };
  27. CRunThreadsData g_RunThreadsData[MAX_THREADS];
  28. int dispatch;
  29. int workcount;
  30. qboolean pacifier;
  31. qboolean threaded;
  32. bool g_bLowPriorityThreads = false;
  33. HANDLE g_ThreadHandles[MAX_THREADS];
  34. /*
  35. =============
  36. GetThreadWork
  37. =============
  38. */
  39. int GetThreadWork (void)
  40. {
  41. int r;
  42. ThreadLock ();
  43. if (dispatch == workcount)
  44. {
  45. ThreadUnlock ();
  46. return -1;
  47. }
  48. UpdatePacifier( (float)dispatch / workcount );
  49. r = dispatch;
  50. dispatch++;
  51. ThreadUnlock ();
  52. return r;
  53. }
  54. ThreadWorkerFn workfunction;
  55. void ThreadWorkerFunction( int iThread, void *pUserData )
  56. {
  57. int work;
  58. while (1)
  59. {
  60. work = GetThreadWork ();
  61. if (work == -1)
  62. break;
  63. workfunction( iThread, work );
  64. }
  65. }
  66. void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, ThreadWorkerFn func)
  67. {
  68. if (numthreads == -1)
  69. ThreadSetDefault ();
  70. workfunction = func;
  71. RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction);
  72. }
  73. /*
  74. ===================================================================
  75. WIN32
  76. ===================================================================
  77. */
  78. int numthreads = -1;
  79. CRITICAL_SECTION crit;
  80. static int enter;
  81. class CCritInit
  82. {
  83. public:
  84. CCritInit()
  85. {
  86. InitializeCriticalSection (&crit);
  87. }
  88. } g_CritInit;
  89. void SetLowPriority()
  90. {
  91. SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
  92. }
  93. void ThreadSetDefault (void)
  94. {
  95. SYSTEM_INFO info;
  96. if (numthreads == -1) // not set manually
  97. {
  98. GetSystemInfo (&info);
  99. numthreads = info.dwNumberOfProcessors;
  100. if (numthreads < 1 || numthreads > 32)
  101. numthreads = 1;
  102. }
  103. Msg ("%i threads\n", numthreads);
  104. }
  105. void ThreadLock (void)
  106. {
  107. if (!threaded)
  108. return;
  109. EnterCriticalSection (&crit);
  110. if (enter)
  111. Error ("Recursive ThreadLock\n");
  112. enter = 1;
  113. }
  114. void ThreadUnlock (void)
  115. {
  116. if (!threaded)
  117. return;
  118. if (!enter)
  119. Error ("ThreadUnlock without lock\n");
  120. enter = 0;
  121. LeaveCriticalSection (&crit);
  122. }
  123. // This runs in the thread and dispatches a RunThreadsFn call.
  124. DWORD WINAPI InternalRunThreadsFn( LPVOID pParameter )
  125. {
  126. CRunThreadsData *pData = (CRunThreadsData*)pParameter;
  127. pData->m_Fn( pData->m_iThread, pData->m_pUserData );
  128. return 0;
  129. }
  130. void RunThreads_Start( RunThreadsFn fn, void *pUserData, ERunThreadsPriority ePriority )
  131. {
  132. Assert( numthreads > 0 );
  133. threaded = true;
  134. if ( numthreads > MAX_TOOL_THREADS )
  135. numthreads = MAX_TOOL_THREADS;
  136. for ( int i=0; i < numthreads ;i++ )
  137. {
  138. g_RunThreadsData[i].m_iThread = i;
  139. g_RunThreadsData[i].m_pUserData = pUserData;
  140. g_RunThreadsData[i].m_Fn = fn;
  141. DWORD dwDummy;
  142. g_ThreadHandles[i] = CreateThread(
  143. NULL, // LPSECURITY_ATTRIBUTES lpsa,
  144. 0, // DWORD cbStack,
  145. InternalRunThreadsFn, // LPTHREAD_START_ROUTINE lpStartAddr,
  146. &g_RunThreadsData[i], // LPVOID lpvThreadParm,
  147. 0, // DWORD fdwCreate,
  148. &dwDummy );
  149. if ( ePriority == k_eRunThreadsPriority_UseGlobalState )
  150. {
  151. if( g_bLowPriorityThreads )
  152. SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_LOWEST );
  153. }
  154. else if ( ePriority == k_eRunThreadsPriority_Idle )
  155. {
  156. SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_IDLE );
  157. }
  158. }
  159. }
  160. void RunThreads_End()
  161. {
  162. WaitForMultipleObjects( numthreads, g_ThreadHandles, TRUE, INFINITE );
  163. for ( int i=0; i < numthreads; i++ )
  164. CloseHandle( g_ThreadHandles[i] );
  165. threaded = false;
  166. }
  167. /*
  168. =============
  169. RunThreadsOn
  170. =============
  171. */
  172. void RunThreadsOn( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData )
  173. {
  174. int start, end;
  175. start = Plat_FloatTime();
  176. dispatch = 0;
  177. workcount = workcnt;
  178. StartPacifier("");
  179. pacifier = showpacifier;
  180. #ifdef _PROFILE
  181. threaded = false;
  182. (*func)( 0 );
  183. return;
  184. #endif
  185. RunThreads_Start( fn, pUserData );
  186. RunThreads_End();
  187. end = Plat_FloatTime();
  188. if (pacifier)
  189. {
  190. EndPacifier(false);
  191. printf (" (%i)\n", end-start);
  192. }
  193. }