//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $Workfile: $ // $Date: $ // //----------------------------------------------------------------------------- // $Log: $ // // $NoKeywords: $ //=============================================================================// #define USED #include #include "cmdlib.h" #define NO_THREAD_NAMES #include "threads.h" #include "pacifier.h" #ifdef MAPBASE // This was suggested in that Source 2013 pull request that fixed Vrad. // I trust their judgement on this. #define MAX_THREADS 32 #else #define MAX_THREADS 16 #endif class CRunThreadsData { public: int m_iThread; void *m_pUserData; RunThreadsFn m_Fn; }; CRunThreadsData g_RunThreadsData[MAX_THREADS]; int dispatch; int workcount; qboolean pacifier; qboolean threaded; bool g_bLowPriorityThreads = false; HANDLE g_ThreadHandles[MAX_THREADS]; /* ============= GetThreadWork ============= */ int GetThreadWork (void) { int r; ThreadLock (); if (dispatch == workcount) { ThreadUnlock (); return -1; } UpdatePacifier( (float)dispatch / workcount ); r = dispatch; dispatch++; ThreadUnlock (); return r; } ThreadWorkerFn workfunction; void ThreadWorkerFunction( int iThread, void *pUserData ) { int work; while (1) { work = GetThreadWork (); if (work == -1) break; workfunction( iThread, work ); } } void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, ThreadWorkerFn func) { if (numthreads == -1) ThreadSetDefault (); workfunction = func; RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); } /* =================================================================== WIN32 =================================================================== */ #ifdef MAPBASE int numthreads = -(MAX_TOOL_THREADS + 1); #else int numthreads = -1; #endif CRITICAL_SECTION crit; static int enter; class CCritInit { public: CCritInit() { InitializeCriticalSection (&crit); } } g_CritInit; void SetLowPriority() { SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS ); } //Threads can be negative; if so, they will be subtracted from the total thread count. void ThreadSetDefault (void) { SYSTEM_INFO info; #ifdef MAPBASE if (numthreads == -(MAX_TOOL_THREADS + 1)) // not set manually #else if (numthreads == -1) // not set manually #endif { GetSystemInfo (&info); numthreads = info.dwNumberOfProcessors; #ifdef MAPBASE if (numthreads > 32) #else if (numthreads < 1 ||numthreads > 32) #endif numthreads = 1; } #ifdef MAPBASE if (numthreads <= 0) { GetSystemInfo(&info); numthreads = info.dwNumberOfProcessors + numthreads; if (numthreads <= 0) Error("\nIncrease the number of threads! Threads: %i, they cannot be negative or 0.\n", numthreads); } #endif Msg ("%i threads\n", numthreads); } void ThreadLock (void) { if (!threaded) return; EnterCriticalSection (&crit); if (enter) Error ("Recursive ThreadLock\n"); enter = 1; } void ThreadUnlock (void) { if (!threaded) return; if (!enter) Error ("ThreadUnlock without lock\n"); enter = 0; LeaveCriticalSection (&crit); } // This runs in the thread and dispatches a RunThreadsFn call. DWORD WINAPI InternalRunThreadsFn( LPVOID pParameter ) { CRunThreadsData *pData = (CRunThreadsData*)pParameter; pData->m_Fn( pData->m_iThread, pData->m_pUserData ); return 0; } void RunThreads_Start( RunThreadsFn fn, void *pUserData, ERunThreadsPriority ePriority ) { Assert( numthreads > 0 ); threaded = true; if ( numthreads > MAX_TOOL_THREADS ) numthreads = MAX_TOOL_THREADS; for ( int i=0; i < numthreads ;i++ ) { g_RunThreadsData[i].m_iThread = i; g_RunThreadsData[i].m_pUserData = pUserData; g_RunThreadsData[i].m_Fn = fn; DWORD dwDummy; g_ThreadHandles[i] = CreateThread( NULL, // LPSECURITY_ATTRIBUTES lpsa, 0, // DWORD cbStack, InternalRunThreadsFn, // LPTHREAD_START_ROUTINE lpStartAddr, &g_RunThreadsData[i], // LPVOID lpvThreadParm, 0, // DWORD fdwCreate, &dwDummy ); if ( ePriority == k_eRunThreadsPriority_UseGlobalState ) { if( g_bLowPriorityThreads ) SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_LOWEST ); } else if ( ePriority == k_eRunThreadsPriority_Idle ) { SetThreadPriority( g_ThreadHandles[i], THREAD_PRIORITY_IDLE ); } } } void RunThreads_End() { WaitForMultipleObjects( numthreads, g_ThreadHandles, TRUE, INFINITE ); for ( int i=0; i < numthreads; i++ ) CloseHandle( g_ThreadHandles[i] ); threaded = false; } /* ============= RunThreadsOn ============= */ void RunThreadsOn( int workcnt, qboolean showpacifier, RunThreadsFn fn, void *pUserData ) { int start, end; start = Plat_FloatTime(); dispatch = 0; workcount = workcnt; StartPacifier(""); pacifier = showpacifier; #ifdef _PROFILE threaded = false; (*func)( 0 ); return; #endif RunThreads_Start( fn, pUserData ); RunThreads_End(); end = Plat_FloatTime(); if (pacifier) { EndPacifier(false); printf (" (%i)\n", end-start); } }