Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.

258 lines
4.3 KiB

5 years ago
//========= 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);
}
}