258 lines
4.3 KiB
C++
258 lines
4.3 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $Workfile: $
|
|
// $Date: $
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// $Log: $
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#define USED
|
|
|
|
#include <windows.h>
|
|
#include "cmdlib.h"
|
|
#define NO_THREAD_NAMES
|
|
#include "threads.h"
|
|
#include "pacifier.h"
|
|
|
|
#define MAX_THREADS 16
|
|
|
|
|
|
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
|
|
|
|
===================================================================
|
|
*/
|
|
|
|
int numthreads = -1;
|
|
CRITICAL_SECTION crit;
|
|
static int enter;
|
|
|
|
|
|
class CCritInit
|
|
{
|
|
public:
|
|
CCritInit()
|
|
{
|
|
InitializeCriticalSection (&crit);
|
|
}
|
|
} g_CritInit;
|
|
|
|
|
|
|
|
void SetLowPriority()
|
|
{
|
|
SetPriorityClass( GetCurrentProcess(), IDLE_PRIORITY_CLASS );
|
|
}
|
|
|
|
|
|
void ThreadSetDefault (void)
|
|
{
|
|
SYSTEM_INFO info;
|
|
|
|
if (numthreads == -1) // not set manually
|
|
{
|
|
GetSystemInfo (&info);
|
|
numthreads = info.dwNumberOfProcessors;
|
|
if (numthreads < 1 || numthreads > 32)
|
|
numthreads = 1;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|