aboutsummaryrefslogtreecommitdiff
path: root/mp/src/public/vstdlib
diff options
context:
space:
mode:
authorNarendra Umate <[email protected]>2013-12-02 23:36:05 -0800
committerNarendra Umate <[email protected]>2013-12-02 23:36:05 -0800
commit8737f191f3b59f001a77bf6c08091109211c1c9f (patch)
treedbbf05c004d9b026f2c1f23f06600fe0add82c36 /mp/src/public/vstdlib
parentUpdate .gitignore. (diff)
parentMake .xcconfigs text files too. (diff)
downloadsource-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.tar.xz
source-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.zip
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'mp/src/public/vstdlib')
-rw-r--r--mp/src/public/vstdlib/IKeyValuesSystem.h96
-rw-r--r--mp/src/public/vstdlib/coroutine.h138
-rw-r--r--mp/src/public/vstdlib/cvar.h50
-rw-r--r--mp/src/public/vstdlib/iprocessutils.h128
-rw-r--r--mp/src/public/vstdlib/jobthread.h2688
-rw-r--r--mp/src/public/vstdlib/osversion.h120
-rw-r--r--mp/src/public/vstdlib/pch_vstdlib.h102
-rw-r--r--mp/src/public/vstdlib/random.h222
-rw-r--r--mp/src/public/vstdlib/vcover.h250
-rw-r--r--mp/src/public/vstdlib/vstdlib.h66
10 files changed, 1930 insertions, 1930 deletions
diff --git a/mp/src/public/vstdlib/IKeyValuesSystem.h b/mp/src/public/vstdlib/IKeyValuesSystem.h
index 893be6cd..1bd5a8ab 100644
--- a/mp/src/public/vstdlib/IKeyValuesSystem.h
+++ b/mp/src/public/vstdlib/IKeyValuesSystem.h
@@ -1,48 +1,48 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-#ifndef VSTDLIB_IKEYVALUESSYSTEM_H
-#define VSTDLIB_IKEYVALUESSYSTEM_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-#include "vstdlib/vstdlib.h"
-
-// handle to a KeyValues key name symbol
-typedef int HKeySymbol;
-#define INVALID_KEY_SYMBOL (-1)
-
-//-----------------------------------------------------------------------------
-// Purpose: Interface to shared data repository for KeyValues (included in vgui_controls.lib)
-// allows for central data storage point of KeyValues symbol table
-//-----------------------------------------------------------------------------
-class IKeyValuesSystem
-{
-public:
- // registers the size of the KeyValues in the specified instance
- // so it can build a properly sized memory pool for the KeyValues objects
- // the sizes will usually never differ but this is for versioning safety
- virtual void RegisterSizeofKeyValues(int size) = 0;
-
- // allocates/frees a KeyValues object from the shared mempool
- virtual void *AllocKeyValuesMemory(int size) = 0;
- virtual void FreeKeyValuesMemory(void *pMem) = 0;
-
- // symbol table access (used for key names)
- virtual HKeySymbol GetSymbolForString( const char *name, bool bCreate = true ) = 0;
- virtual const char *GetStringForSymbol(HKeySymbol symbol) = 0;
-
- // for debugging, adds KeyValues record into global list so we can track memory leaks
- virtual void AddKeyValuesToMemoryLeakList(void *pMem, HKeySymbol name) = 0;
- virtual void RemoveKeyValuesFromMemoryLeakList(void *pMem) = 0;
-};
-
-VSTDLIB_INTERFACE IKeyValuesSystem *KeyValuesSystem();
-
-// #define KEYVALUESSYSTEM_INTERFACE_VERSION "KeyValuesSystem002"
-
-#endif // VSTDLIB_IKEYVALUESSYSTEM_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#ifndef VSTDLIB_IKEYVALUESSYSTEM_H
+#define VSTDLIB_IKEYVALUESSYSTEM_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vstdlib/vstdlib.h"
+
+// handle to a KeyValues key name symbol
+typedef int HKeySymbol;
+#define INVALID_KEY_SYMBOL (-1)
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface to shared data repository for KeyValues (included in vgui_controls.lib)
+// allows for central data storage point of KeyValues symbol table
+//-----------------------------------------------------------------------------
+class IKeyValuesSystem
+{
+public:
+ // registers the size of the KeyValues in the specified instance
+ // so it can build a properly sized memory pool for the KeyValues objects
+ // the sizes will usually never differ but this is for versioning safety
+ virtual void RegisterSizeofKeyValues(int size) = 0;
+
+ // allocates/frees a KeyValues object from the shared mempool
+ virtual void *AllocKeyValuesMemory(int size) = 0;
+ virtual void FreeKeyValuesMemory(void *pMem) = 0;
+
+ // symbol table access (used for key names)
+ virtual HKeySymbol GetSymbolForString( const char *name, bool bCreate = true ) = 0;
+ virtual const char *GetStringForSymbol(HKeySymbol symbol) = 0;
+
+ // for debugging, adds KeyValues record into global list so we can track memory leaks
+ virtual void AddKeyValuesToMemoryLeakList(void *pMem, HKeySymbol name) = 0;
+ virtual void RemoveKeyValuesFromMemoryLeakList(void *pMem) = 0;
+};
+
+VSTDLIB_INTERFACE IKeyValuesSystem *KeyValuesSystem();
+
+// #define KEYVALUESSYSTEM_INTERFACE_VERSION "KeyValuesSystem002"
+
+#endif // VSTDLIB_IKEYVALUESSYSTEM_H
diff --git a/mp/src/public/vstdlib/coroutine.h b/mp/src/public/vstdlib/coroutine.h
index c367ffa2..797324df 100644
--- a/mp/src/public/vstdlib/coroutine.h
+++ b/mp/src/public/vstdlib/coroutine.h
@@ -1,69 +1,69 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: setjmp/longjmp based cooperative multitasking system
-//
-//=============================================================================
-
-#ifndef COROUTINE_H
-#define COROUTINE_H
-#pragma once
-
-#include "vstdlib/vstdlib.h"
-
-// enable this to do coroutine tracing
-// this will tell coroutine API users to set coroutine names
-// #define COROUTINE_TRACE
-
-//-----------------------------------------------------------------------------
-// Purpose: handles running coroutines
-// setjmp/longjmp based cooperative multitasking system
-//-----------------------------------------------------------------------------
-
-// coroutine callback
-typedef void (__cdecl *CoroutineFunc_t )(void *);
-
-// handle to a coroutine
-typedef int32 HCoroutine;
-
-// creates a new coroutine
-// no coroutine code is executed until Coroutine_Continue() is called
-VSTDLIB_INTERFACE HCoroutine Coroutine_Create( CoroutineFunc_t pFunc, void *pvParam );
-
-// continues the specified coroutine
-// returns true if the coroutine is still running, false otherwise
-VSTDLIB_INTERFACE bool Coroutine_Continue( HCoroutine hCoroutine, const char *pchName = NULL );
-
-// cancels a currently running coroutine
-VSTDLIB_INTERFACE void Coroutine_Cancel( HCoroutine hCoroutine );
-
-// 'load' a coroutine only to debug it - immediately breaks into debugger
-// when continued, pops back to the prior coroutine
-VSTDLIB_INTERFACE void Coroutine_DebugBreak( HCoroutine hCoroutine );
-
-// Load a coroutine and generate an assert. Used to get a minidump of a job
-VSTDLIB_INTERFACE void Coroutine_DebugAssert( HCoroutine hCoroutine, const char *pchMsg );
-
-// called from the coroutine to return control to the main thread
-VSTDLIB_INTERFACE void Coroutine_YieldToMain();
-
-// returns true if the code is currently running inside of a coroutine
-VSTDLIB_INTERFACE bool Coroutine_IsActive();
-
-// returns a handle the currently active coroutine
-VSTDLIB_INTERFACE HCoroutine Coroutine_GetCurrentlyActive();
-
-// call when a thread is quiting to release any per-thread memory
-VSTDLIB_INTERFACE void Coroutine_ReleaseThreadMemory();
-
-// runs a self-test of the coroutine system
-VSTDLIB_INTERFACE bool Coroutine_Test();
-
-// memory validation
-VSTDLIB_INTERFACE void Coroutine_ValidateGlobals( class CValidator &validator );
-
-// for debugging purposes - returns stack depth of current coroutine
-VSTDLIB_INTERFACE size_t Coroutine_GetStackDepth();
-
-
-
-#endif // COROUTINE_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: setjmp/longjmp based cooperative multitasking system
+//
+//=============================================================================
+
+#ifndef COROUTINE_H
+#define COROUTINE_H
+#pragma once
+
+#include "vstdlib/vstdlib.h"
+
+// enable this to do coroutine tracing
+// this will tell coroutine API users to set coroutine names
+// #define COROUTINE_TRACE
+
+//-----------------------------------------------------------------------------
+// Purpose: handles running coroutines
+// setjmp/longjmp based cooperative multitasking system
+//-----------------------------------------------------------------------------
+
+// coroutine callback
+typedef void (__cdecl *CoroutineFunc_t )(void *);
+
+// handle to a coroutine
+typedef int32 HCoroutine;
+
+// creates a new coroutine
+// no coroutine code is executed until Coroutine_Continue() is called
+VSTDLIB_INTERFACE HCoroutine Coroutine_Create( CoroutineFunc_t pFunc, void *pvParam );
+
+// continues the specified coroutine
+// returns true if the coroutine is still running, false otherwise
+VSTDLIB_INTERFACE bool Coroutine_Continue( HCoroutine hCoroutine, const char *pchName = NULL );
+
+// cancels a currently running coroutine
+VSTDLIB_INTERFACE void Coroutine_Cancel( HCoroutine hCoroutine );
+
+// 'load' a coroutine only to debug it - immediately breaks into debugger
+// when continued, pops back to the prior coroutine
+VSTDLIB_INTERFACE void Coroutine_DebugBreak( HCoroutine hCoroutine );
+
+// Load a coroutine and generate an assert. Used to get a minidump of a job
+VSTDLIB_INTERFACE void Coroutine_DebugAssert( HCoroutine hCoroutine, const char *pchMsg );
+
+// called from the coroutine to return control to the main thread
+VSTDLIB_INTERFACE void Coroutine_YieldToMain();
+
+// returns true if the code is currently running inside of a coroutine
+VSTDLIB_INTERFACE bool Coroutine_IsActive();
+
+// returns a handle the currently active coroutine
+VSTDLIB_INTERFACE HCoroutine Coroutine_GetCurrentlyActive();
+
+// call when a thread is quiting to release any per-thread memory
+VSTDLIB_INTERFACE void Coroutine_ReleaseThreadMemory();
+
+// runs a self-test of the coroutine system
+VSTDLIB_INTERFACE bool Coroutine_Test();
+
+// memory validation
+VSTDLIB_INTERFACE void Coroutine_ValidateGlobals( class CValidator &validator );
+
+// for debugging purposes - returns stack depth of current coroutine
+VSTDLIB_INTERFACE size_t Coroutine_GetStackDepth();
+
+
+
+#endif // COROUTINE_H
diff --git a/mp/src/public/vstdlib/cvar.h b/mp/src/public/vstdlib/cvar.h
index 57a39adc..63734411 100644
--- a/mp/src/public/vstdlib/cvar.h
+++ b/mp/src/public/vstdlib/cvar.h
@@ -1,25 +1,25 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-#if !defined( CVAR_H )
-#define CVAR_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-#include "vstdlib/vstdlib.h"
-#include "icvar.h"
-
-
-//-----------------------------------------------------------------------------
-// Returns a CVar dictionary for tool usage
-//-----------------------------------------------------------------------------
-VSTDLIB_INTERFACE CreateInterfaceFn VStdLib_GetICVarFactory();
-
-
-#endif // CVAR_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#if !defined( CVAR_H )
+#define CVAR_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vstdlib/vstdlib.h"
+#include "icvar.h"
+
+
+//-----------------------------------------------------------------------------
+// Returns a CVar dictionary for tool usage
+//-----------------------------------------------------------------------------
+VSTDLIB_INTERFACE CreateInterfaceFn VStdLib_GetICVarFactory();
+
+
+#endif // CVAR_H
diff --git a/mp/src/public/vstdlib/iprocessutils.h b/mp/src/public/vstdlib/iprocessutils.h
index 6eb64486..8e4d37f8 100644
--- a/mp/src/public/vstdlib/iprocessutils.h
+++ b/mp/src/public/vstdlib/iprocessutils.h
@@ -1,64 +1,64 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//===========================================================================//
-
-#ifndef IPROCESSUTILS_H
-#define IPROCESSUTILS_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-#include "appframework/IAppSystem.h"
-
-
-//-----------------------------------------------------------------------------
-// Handle to a process
-//-----------------------------------------------------------------------------
-typedef int ProcessHandle_t;
-enum
-{
- PROCESS_HANDLE_INVALID = 0,
-};
-
-
-//-----------------------------------------------------------------------------
-// Interface version
-//-----------------------------------------------------------------------------
-#define PROCESS_UTILS_INTERFACE_VERSION "VProcessUtils001"
-
-
-//-----------------------------------------------------------------------------
-// Interface for makefiles to build differently depending on where they are run from
-//-----------------------------------------------------------------------------
-abstract_class IProcessUtils : public IAppSystem
-{
-public:
- // Starts, stops a process
- virtual ProcessHandle_t StartProcess( const char *pCommandLine, bool bConnectStdPipes ) = 0;
- virtual ProcessHandle_t StartProcess( int argc, const char **argv, bool bConnectStdPipes ) = 0;
- virtual void CloseProcess( ProcessHandle_t hProcess ) = 0;
- virtual void AbortProcess( ProcessHandle_t hProcess ) = 0;
-
- // Returns true if a process is complete
- virtual bool IsProcessComplete( ProcessHandle_t hProcess ) = 0;
-
- // Waits until a process is complete
- virtual void WaitUntilProcessCompletes( ProcessHandle_t hProcess ) = 0;
-
- // Methods used to write input into a process
- virtual int SendProcessInput( ProcessHandle_t hProcess, char *pBuf, int nBufLen ) = 0;
-
- // Methods used to read output back from a process
- virtual int GetProcessOutputSize( ProcessHandle_t hProcess ) = 0;
- virtual int GetProcessOutput( ProcessHandle_t hProcess, char *pBuf, int nBufLen ) = 0;
-
- // Returns the exit code for the process. Doesn't work unless the process is complete
- virtual int GetProcessExitCode( ProcessHandle_t hProcess ) = 0;
-};
-
-
-#endif // IPROCESSUTILS_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef IPROCESSUTILS_H
+#define IPROCESSUTILS_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "appframework/IAppSystem.h"
+
+
+//-----------------------------------------------------------------------------
+// Handle to a process
+//-----------------------------------------------------------------------------
+typedef int ProcessHandle_t;
+enum
+{
+ PROCESS_HANDLE_INVALID = 0,
+};
+
+
+//-----------------------------------------------------------------------------
+// Interface version
+//-----------------------------------------------------------------------------
+#define PROCESS_UTILS_INTERFACE_VERSION "VProcessUtils001"
+
+
+//-----------------------------------------------------------------------------
+// Interface for makefiles to build differently depending on where they are run from
+//-----------------------------------------------------------------------------
+abstract_class IProcessUtils : public IAppSystem
+{
+public:
+ // Starts, stops a process
+ virtual ProcessHandle_t StartProcess( const char *pCommandLine, bool bConnectStdPipes ) = 0;
+ virtual ProcessHandle_t StartProcess( int argc, const char **argv, bool bConnectStdPipes ) = 0;
+ virtual void CloseProcess( ProcessHandle_t hProcess ) = 0;
+ virtual void AbortProcess( ProcessHandle_t hProcess ) = 0;
+
+ // Returns true if a process is complete
+ virtual bool IsProcessComplete( ProcessHandle_t hProcess ) = 0;
+
+ // Waits until a process is complete
+ virtual void WaitUntilProcessCompletes( ProcessHandle_t hProcess ) = 0;
+
+ // Methods used to write input into a process
+ virtual int SendProcessInput( ProcessHandle_t hProcess, char *pBuf, int nBufLen ) = 0;
+
+ // Methods used to read output back from a process
+ virtual int GetProcessOutputSize( ProcessHandle_t hProcess ) = 0;
+ virtual int GetProcessOutput( ProcessHandle_t hProcess, char *pBuf, int nBufLen ) = 0;
+
+ // Returns the exit code for the process. Doesn't work unless the process is complete
+ virtual int GetProcessExitCode( ProcessHandle_t hProcess ) = 0;
+};
+
+
+#endif // IPROCESSUTILS_H
diff --git a/mp/src/public/vstdlib/jobthread.h b/mp/src/public/vstdlib/jobthread.h
index ed453cf9..559937b3 100644
--- a/mp/src/public/vstdlib/jobthread.h
+++ b/mp/src/public/vstdlib/jobthread.h
@@ -1,1344 +1,1344 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: A utility for a discrete job-oriented worker thread.
-//
-// The class CThreadPool is both the job queue, and the
-// worker thread. Except when the main thread attempts to
-// synchronously execute a job, most of the inter-thread locking
-// on the queue.
-//
-// The queue threading model uses a manual reset event for optimal
-// throughput. Adding to the queue is guarded by a semaphore that
-// will block the inserting thread if the queue has overflown.
-// This prevents the worker thread from being starved out even if
-// not running at a higher priority than the master thread.
-//
-// The thread function waits for jobs, services jobs, and manages
-// communication between the worker and master threads. The nature
-// of the work is opaque to the Executer.
-//
-// CJob instances actually do the work. The base class
-// calls virtual methods for job primitives, so derivations don't
-// need to worry about threading models. All of the variants of
-// job and OS can be expressed in this hierarchy. Instances of
-// CJob are the items placed in the queue, and by
-// overriding the job primitives they are the manner by which
-// users of the Executer control the state of the job.
-//
-//=============================================================================
-
-#include <limits.h>
-#include "tier0/threadtools.h"
-#include "tier1/refcount.h"
-#include "tier1/utllinkedlist.h"
-#include "tier1/utlvector.h"
-#include "tier1/functors.h"
-#include "tier0/vprof_telemetry.h"
-
-#include "vstdlib/vstdlib.h"
-
-#ifndef JOBTHREAD_H
-#define JOBTHREAD_H
-
-#ifdef AddJob // windows.h print function collisions
-#undef AddJob
-#undef GetJob
-#endif
-
-#ifdef VSTDLIB_DLL_EXPORT
-#define JOB_INTERFACE DLL_EXPORT
-#define JOB_OVERLOAD DLL_GLOBAL_EXPORT
-#define JOB_CLASS DLL_CLASS_EXPORT
-#else
-#define JOB_INTERFACE DLL_IMPORT
-#define JOB_OVERLOAD DLL_GLOBAL_IMPORT
-#define JOB_CLASS DLL_CLASS_IMPORT
-#endif
-
-#if defined( _WIN32 )
-#pragma once
-#endif
-
-//-----------------------------------------------------------------------------
-//
-//-----------------------------------------------------------------------------
-
-class CJob;
-
-//-----------------------------------------------------------------------------
-//
-//-----------------------------------------------------------------------------
-enum JobStatusEnum_t
-{
- // Use negative for errors
- JOB_OK, // operation is successful
- JOB_STATUS_PENDING, // file is properly queued, waiting for service
- JOB_STATUS_INPROGRESS, // file is being accessed
- JOB_STATUS_ABORTED, // file was aborted by caller
- JOB_STATUS_UNSERVICED, // file is not yet queued
-};
-
-typedef int JobStatus_t;
-
-enum JobFlags_t
-{
- JF_IO = ( 1 << 0 ), // The job primarily blocks on IO or hardware
- JF_BOOST_THREAD = ( 1 << 1 ), // Up the thread priority to max allowed while processing task
- JF_SERIAL = ( 1 << 2 ), // Job cannot be executed out of order relative to other "strict" jobs
- JF_QUEUE = ( 1 << 3 ), // Queue it, even if not an IO job
-};
-
-enum JobPriority_t
-{
- JP_LOW,
- JP_NORMAL,
- JP_HIGH
-};
-
-#define TP_MAX_POOL_THREADS 64
-struct ThreadPoolStartParams_t
-{
- ThreadPoolStartParams_t( bool bIOThreads = false, unsigned nThreads = -1, int *pAffinities = NULL, ThreeState_t fDistribute = TRS_NONE, unsigned nStackSize = -1, int iThreadPriority = SHRT_MIN )
- : bIOThreads( bIOThreads ), nThreads( nThreads ), fDistribute( fDistribute ), nStackSize( nStackSize ), iThreadPriority( iThreadPriority ), nThreadsMax( -1 )
- {
- bExecOnThreadPoolThreadsOnly = false;
-
- bUseAffinityTable = ( pAffinities != NULL ) && ( fDistribute == TRS_TRUE ) && ( nThreads != -1 );
- if ( bUseAffinityTable )
- {
- // user supplied an optional 1:1 affinity mapping to override normal distribute behavior
- nThreads = MIN( TP_MAX_POOL_THREADS, nThreads );
- for ( unsigned int i = 0; i < nThreads; i++ )
- {
- iAffinityTable[i] = pAffinities[i];
- }
- }
- }
-
- int nThreads;
- int nThreadsMax;
- ThreeState_t fDistribute;
- int nStackSize;
- int iThreadPriority;
- int iAffinityTable[TP_MAX_POOL_THREADS];
-
- bool bIOThreads : 1;
- bool bUseAffinityTable : 1;
- bool bExecOnThreadPoolThreadsOnly : 1;
-};
-
-//-----------------------------------------------------------------------------
-//
-// IThreadPool
-//
-//-----------------------------------------------------------------------------
-
-typedef bool (*JobFilter_t)( CJob * );
-
-//---------------------------------------------------------
-// Messages supported through the CallWorker() method
-//---------------------------------------------------------
-enum ThreadPoolMessages_t
-{
- TPM_EXIT, // Exit the thread
- TPM_SUSPEND, // Suspend after next operation
- TPM_RUNFUNCTOR, // Run functor, reply when done.
-};
-
-//---------------------------------------------------------
-
-abstract_class IThreadPool : public IRefCounted
-{
-public:
- virtual ~IThreadPool() {};
-
- //-----------------------------------------------------
- // Thread functions
- //-----------------------------------------------------
- virtual bool Start( const ThreadPoolStartParams_t &startParams = ThreadPoolStartParams_t() ) = 0;
- virtual bool Stop( int timeout = TT_INFINITE ) = 0;
-
- //-----------------------------------------------------
- // Functions for any thread
- //-----------------------------------------------------
- virtual unsigned GetJobCount() = 0;
- virtual int NumThreads() = 0;
- virtual int NumIdleThreads() = 0;
-
- //-----------------------------------------------------
- // Pause/resume processing jobs
- //-----------------------------------------------------
- virtual int SuspendExecution() = 0;
- virtual int ResumeExecution() = 0;
-
- //-----------------------------------------------------
- // Offer the current thread to the pool
- //-----------------------------------------------------
- virtual int YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) = 0;
- virtual int YieldWait( CJob **, int nJobs, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) = 0;
- virtual void Yield( unsigned timeout ) = 0;
-
- bool YieldWait( CThreadEvent &event, unsigned timeout = TT_INFINITE );
- bool YieldWait( CJob *, unsigned timeout = TT_INFINITE );
-
- //-----------------------------------------------------
- // Add a native job to the queue (master thread)
- //-----------------------------------------------------
- virtual void AddJob( CJob * ) = 0;
-
- //-----------------------------------------------------
- // All threads execute pFunctor asap. Thread will either wake up
- // and execute or execute pFunctor right after completing current job and
- // before looking for another job.
- //-----------------------------------------------------
- virtual void ExecuteHighPriorityFunctor( CFunctor *pFunctor ) = 0;
-
- //-----------------------------------------------------
- // Add an function object to the queue (master thread)
- //-----------------------------------------------------
- virtual void AddFunctor( CFunctor *pFunctor, CJob **ppJob = NULL, const char *pszDescription = NULL, unsigned flags = 0 ) { AddFunctorInternal( RetAddRef( pFunctor ), ppJob, pszDescription, flags ); }
-
- //-----------------------------------------------------
- // Change the priority of an active job
- //-----------------------------------------------------
- virtual void ChangePriority( CJob *p, JobPriority_t priority ) = 0;
-
- //-----------------------------------------------------
- // Bulk job manipulation (blocking)
- //-----------------------------------------------------
- int ExecuteAll( JobFilter_t pfnFilter = NULL ) { return ExecuteToPriority( JP_LOW, pfnFilter ); }
- virtual int ExecuteToPriority( JobPriority_t toPriority, JobFilter_t pfnFilter = NULL ) = 0;
- virtual int AbortAll() = 0;
-
- //-----------------------------------------------------
- virtual void Reserved1() = 0;
-
- //-----------------------------------------------------
- // Add an arbitrary call to the queue (master thread)
- //
- // Avert thy eyes! Imagine rather:
- //
- // CJob *AddCall( <function>, [args1, [arg2,]...]
- // CJob *AddCall( <object>, <function>, [args1, [arg2,]...]
- // CJob *AddRefCall( <object>, <function>, [args1, [arg2,]...]
- // CJob *QueueCall( <function>, [args1, [arg2,]...]
- // CJob *QueueCall( <object>, <function>, [args1, [arg2,]...]
- //-----------------------------------------------------
-
- #define DEFINE_NONMEMBER_ADD_CALL(N) \
- template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *AddCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- if ( !NumIdleThreads() ) \
- { \
- pJob = GetDummyJob(); \
- FunctorDirectCall( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
- } \
- \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_MEMBER_ADD_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- if ( !NumIdleThreads() ) \
- { \
- pJob = GetDummyJob(); \
- FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
- } \
- \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_CONST_MEMBER_ADD_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- if ( !NumIdleThreads() ) \
- { \
- pJob = GetDummyJob(); \
- FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
- } \
- \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_REF_COUNTING_MEMBER_ADD_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- if ( !NumIdleThreads() ) \
- { \
- pJob = GetDummyJob(); \
- FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
- } \
- \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- if ( !NumIdleThreads() ) \
- { \
- pJob = GetDummyJob(); \
- FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
- } \
- \
- return pJob; \
- }
-
- //-----------------------------------------------------------------------------
-
- #define DEFINE_NONMEMBER_QUEUE_CALL(N) \
- template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_MEMBER_QUEUE_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_CONST_MEMBER_QUEUE_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
- return pJob; \
- }
-
- //-------------------------------------
-
- #define DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
- CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- CJob *pJob; \
- AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
- \
- return pJob; \
- }
-
- FUNC_GENERATE_ALL( DEFINE_NONMEMBER_ADD_CALL );
- FUNC_GENERATE_ALL( DEFINE_MEMBER_ADD_CALL );
- FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_ADD_CALL );
- FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_ADD_CALL );
- FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL );
- FUNC_GENERATE_ALL( DEFINE_NONMEMBER_QUEUE_CALL );
- FUNC_GENERATE_ALL( DEFINE_MEMBER_QUEUE_CALL );
- FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_QUEUE_CALL );
- FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL );
- FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL );
-
- #undef DEFINE_NONMEMBER_ADD_CALL
- #undef DEFINE_MEMBER_ADD_CALL
- #undef DEFINE_CONST_MEMBER_ADD_CALL
- #undef DEFINE_REF_COUNTING_MEMBER_ADD_CALL
- #undef DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL
- #undef DEFINE_NONMEMBER_QUEUE_CALL
- #undef DEFINE_MEMBER_QUEUE_CALL
- #undef DEFINE_CONST_MEMBER_QUEUE_CALL
- #undef DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL
- #undef DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL
-
-private:
- virtual void AddFunctorInternal( CFunctor *, CJob ** = NULL, const char *pszDescription = NULL, unsigned flags = 0 ) = 0;
-
- //-----------------------------------------------------
- // Services for internal use by job instances
- //-----------------------------------------------------
- friend class CJob;
-
- virtual CJob *GetDummyJob() = 0;
-
-public:
- virtual void Distribute( bool bDistribute = true, int *pAffinityTable = NULL ) = 0;
-
- virtual bool Start( const ThreadPoolStartParams_t &startParams, const char *pszNameOverride ) = 0;
-};
-
-//-----------------------------------------------------------------------------
-
-JOB_INTERFACE IThreadPool *CreateThreadPool();
-JOB_INTERFACE void DestroyThreadPool( IThreadPool *pPool );
-
-//-------------------------------------
-
-JOB_INTERFACE void RunThreadPoolTests();
-
-//-----------------------------------------------------------------------------
-
-JOB_INTERFACE IThreadPool *g_pThreadPool;
-
-//-----------------------------------------------------------------------------
-// Class to combine the metadata for an operation and the ability to perform
-// the operation. Meant for inheritance. All functions inline, defers to executor
-//-----------------------------------------------------------------------------
-DECLARE_POINTER_HANDLE( ThreadPoolData_t );
-#define JOB_NO_DATA ((ThreadPoolData_t)-1)
-
-class CJob : public CRefCounted1<IRefCounted, CRefCountServiceMT>
-{
-public:
- CJob( JobPriority_t priority = JP_NORMAL )
- : m_status( JOB_STATUS_UNSERVICED ),
- m_ThreadPoolData( JOB_NO_DATA ),
- m_priority( priority ),
- m_flags( 0 ),
- m_pThreadPool( NULL ),
- m_CompleteEvent( true ),
- m_iServicingThread( -1 )
- {
- m_szDescription[ 0 ] = 0;
- }
-
- //-----------------------------------------------------
- // Priority (not thread safe)
- //-----------------------------------------------------
- void SetPriority( JobPriority_t priority ) { m_priority = priority; }
- JobPriority_t GetPriority() const { return m_priority; }
-
- //-----------------------------------------------------
-
- void SetFlags( unsigned flags ) { m_flags = flags; }
- unsigned GetFlags() const { return m_flags; }
-
- //-----------------------------------------------------
-
- void SetServiceThread( int iServicingThread ) { m_iServicingThread = (char)iServicingThread; }
- int GetServiceThread() const { return m_iServicingThread; }
- void ClearServiceThread() { m_iServicingThread = -1; }
-
- //-----------------------------------------------------
- // Fast queries
- //-----------------------------------------------------
- bool Executed() const { return ( m_status == JOB_OK ); }
- bool CanExecute() const { return ( m_status == JOB_STATUS_PENDING || m_status == JOB_STATUS_UNSERVICED ); }
- bool IsFinished() const { return ( m_status != JOB_STATUS_PENDING && m_status != JOB_STATUS_INPROGRESS && m_status != JOB_STATUS_UNSERVICED ); }
- JobStatus_t GetStatus() const { return m_status; }
-
- /// Slam the status to a particular value. This is named "slam" instead of "set,"
- /// to warn you that it should only be used in unusual situations. Otherwise, the
- /// job manager really should manage the status for you, and you should not manhandle it.
- void SlamStatus(JobStatus_t s) { m_status = s; }
-
- //-----------------------------------------------------
- // Try to acquire ownership (to satisfy). If you take the lock, you must either execute or abort.
- //-----------------------------------------------------
- bool TryLock() { return m_mutex.TryLock(); }
- void Lock() { m_mutex.Lock(); }
- void Unlock() { m_mutex.Unlock(); }
-
- //-----------------------------------------------------
- // Thread event support (safe for NULL this to simplify code )
- //-----------------------------------------------------
- bool WaitForFinish( uint32 dwTimeout = TT_INFINITE ) { if (!this) return true; return ( !IsFinished() ) ? g_pThreadPool->YieldWait( this, dwTimeout ) : true; }
- bool WaitForFinishAndRelease( uint32 dwTimeout = TT_INFINITE ) { if (!this) return true; bool bResult = WaitForFinish( dwTimeout); Release(); return bResult; }
- CThreadEvent *AccessEvent() { return &m_CompleteEvent; }
-
- //-----------------------------------------------------
- // Perform the job
- //-----------------------------------------------------
- JobStatus_t Execute();
- JobStatus_t TryExecute();
- JobStatus_t ExecuteAndRelease() { JobStatus_t status = Execute(); Release(); return status; }
- JobStatus_t TryExecuteAndRelease() { JobStatus_t status = TryExecute(); Release(); return status; }
-
- //-----------------------------------------------------
- // Terminate the job, discard if partially or wholly fulfilled
- //-----------------------------------------------------
- JobStatus_t Abort( bool bDiscard = true );
-
- virtual char const *Describe() { return m_szDescription[ 0 ] ? m_szDescription : "Job"; }
- virtual void SetDescription( const char *pszDescription )
- {
- if( pszDescription )
- {
- Q_strncpy( m_szDescription, pszDescription, sizeof( m_szDescription ) );
- }
- else
- {
- m_szDescription[ 0 ] = 0;
- }
- }
-
-private:
- //-----------------------------------------------------
- friend class CThreadPool;
-
- JobStatus_t m_status;
- JobPriority_t m_priority;
- CThreadMutex m_mutex;
- unsigned char m_flags;
- char m_iServicingThread;
- short m_reserved;
- ThreadPoolData_t m_ThreadPoolData;
- IThreadPool * m_pThreadPool;
- CThreadEvent m_CompleteEvent;
- char m_szDescription[ 32 ];
-
-private:
- //-----------------------------------------------------
- CJob( const CJob &fromRequest );
- void operator=(const CJob &fromRequest );
-
- virtual JobStatus_t DoExecute() = 0;
- virtual JobStatus_t DoAbort( bool bDiscard ) { return JOB_STATUS_ABORTED; }
- virtual void DoCleanup() {}
-};
-
-//-----------------------------------------------------------------------------
-
-class CFunctorJob : public CJob
-{
-public:
- CFunctorJob( CFunctor *pFunctor, const char *pszDescription = NULL )
- : m_pFunctor( pFunctor )
- {
- if ( pszDescription )
- {
- Q_strncpy( m_szDescription, pszDescription, sizeof(m_szDescription) );
- }
- else
- {
- m_szDescription[0] = 0;
- }
- }
-
- virtual JobStatus_t DoExecute()
- {
- (*m_pFunctor)();
- return JOB_OK;
- }
-
- const char *Describe()
- {
- return m_szDescription;
- }
-
-private:
- CRefPtr<CFunctor> m_pFunctor;
- char m_szDescription[16];
-};
-
-//-----------------------------------------------------------------------------
-// Utility for managing multiple jobs
-//-----------------------------------------------------------------------------
-
-class CJobSet
-{
-public:
- CJobSet( CJob *pJob = NULL )
- {
- if ( pJob )
- {
- m_jobs.AddToTail( pJob );
- }
- }
-
- CJobSet( CJob **ppJobs, int nJobs )
- {
- if ( ppJobs )
- {
- m_jobs.AddMultipleToTail( nJobs, ppJobs );
- }
- }
-
- ~CJobSet()
- {
- for ( int i = 0; i < m_jobs.Count(); i++ )
- {
- m_jobs[i]->Release();
- }
- }
-
- void operator+=( CJob *pJob )
- {
- m_jobs.AddToTail( pJob );
- }
-
- void operator-=( CJob *pJob )
- {
- m_jobs.FindAndRemove( pJob );
- }
-
- void Execute( bool bRelease = true )
- {
- for ( int i = 0; i < m_jobs.Count(); i++ )
- {
- m_jobs[i]->Execute();
- if ( bRelease )
- {
- m_jobs[i]->Release();
- }
- }
-
- if ( bRelease )
- {
- m_jobs.RemoveAll();
- }
- }
-
- void Abort( bool bRelease = true )
- {
- for ( int i = 0; i < m_jobs.Count(); i++ )
- {
- m_jobs[i]->Abort();
- if ( bRelease )
- {
- m_jobs[i]->Release();
- }
- }
-
- if ( bRelease )
- {
- m_jobs.RemoveAll();
- }
- }
-
- void WaitForFinish( bool bRelease = true )
- {
- for ( int i = 0; i < m_jobs.Count(); i++ )
- {
- m_jobs[i]->WaitForFinish();
- if ( bRelease )
- {
- m_jobs[i]->Release();
- }
- }
-
- if ( bRelease )
- {
- m_jobs.RemoveAll();
- }
- }
-
- void WaitForFinish( IThreadPool *pPool, bool bRelease = true )
- {
- pPool->YieldWait( m_jobs.Base(), m_jobs.Count() );
-
- if ( bRelease )
- {
- for ( int i = 0; i < m_jobs.Count(); i++ )
- {
- m_jobs[i]->Release();
- }
-
- m_jobs.RemoveAll();
- }
- }
-
-private:
- CUtlVectorFixed<CJob *, 16> m_jobs;
-};
-
-//-----------------------------------------------------------------------------
-// Job helpers
-//-----------------------------------------------------------------------------
-
-#define ThreadExecute g_pThreadPool->QueueCall
-#define ThreadExecuteRef g_pThreadPool->QueueRefCall
-
-#define BeginExecuteParallel() do { CJobSet jobSet
-#define EndExecuteParallel() jobSet.WaitForFinish( g_pThreadPool ); } while (0)
-
-#define ExecuteParallel jobSet += g_pThreadPool->QueueCall
-#define ExecuteRefParallel jobSet += g_pThreadPool->QueueCallRef
-
-
-//-----------------------------------------------------------------------------
-// Work splitting: array split, best when cost per item is roughly equal
-//-----------------------------------------------------------------------------
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4389)
-#pragma warning(disable:4018)
-#pragma warning(disable:4701)
-#endif
-
-#define DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL(N) \
- template <typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N, typename ITERTYPE1, typename ITERTYPE2> \
- void IterRangeParallel(FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_ADDL_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- const int MAX_THREADS = 16; \
- int nIdle = g_pThreadPool->NumIdleThreads(); \
- ITERTYPE1 range = to - from; \
- int nThreads = MIN( nIdle + 1, range ); \
- if ( nThreads > MAX_THREADS ) \
- { \
- nThreads = MAX_THREADS; \
- } \
- if ( nThreads < 2 ) \
- { \
- FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- ITERTYPE1 nIncrement = range / nThreads; \
- \
- CJobSet jobSet; \
- while ( --nThreads ) \
- { \
- ITERTYPE2 thisTo = from + nIncrement; \
- jobSet += g_pThreadPool->AddCall( pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \
- from = thisTo; \
- } \
- FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
- jobSet.WaitForFinish( g_pThreadPool ); \
- } \
- \
- }
-
-FUNC_GENERATE_ALL( DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL );
-
-#define DEFINE_MEMBER_ITER_RANGE_PARALLEL(N) \
- template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N, typename ITERTYPE1, typename ITERTYPE2> \
- void IterRangeParallel(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_ADDL_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \
- { \
- const int MAX_THREADS = 16; \
- int nIdle = g_pThreadPool->NumIdleThreads(); \
- ITERTYPE1 range = to - from; \
- int nThreads = MIN( nIdle + 1, range ); \
- if ( nThreads > MAX_THREADS ) \
- { \
- nThreads = MAX_THREADS; \
- } \
- if ( nThreads < 2 ) \
- { \
- FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
- } \
- else \
- { \
- ITERTYPE1 nIncrement = range / nThreads; \
- \
- CJobSet jobSet; \
- while ( --nThreads ) \
- { \
- ITERTYPE2 thisTo = from + nIncrement; \
- jobSet += g_pThreadPool->AddCall( pObject, pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \
- from = thisTo; \
- } \
- FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
- jobSet.WaitForFinish( g_pThreadPool ); \
- } \
- \
- }
-
-FUNC_GENERATE_ALL( DEFINE_MEMBER_ITER_RANGE_PARALLEL );
-
-//-----------------------------------------------------------------------------
-// Work splitting: competitive, best when cost per item varies a lot
-//-----------------------------------------------------------------------------
-
-template <typename T>
-class CJobItemProcessor
-{
-public:
- typedef T ItemType_t;
- void Begin() {}
- // void Process( ItemType_t & ) {}
- void End() {}
-};
-
-template <typename T>
-class CFuncJobItemProcessor : public CJobItemProcessor<T>
-{
-public:
- void Init(void (*pfnProcess)( T & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL )
- {
- m_pfnProcess = pfnProcess;
- m_pfnBegin = pfnBegin;
- m_pfnEnd = pfnEnd;
- }
-
- //CFuncJobItemProcessor(OBJECT_TYPE_PTR pObject, void (FUNCTION_CLASS::*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL );
- void Begin() { if ( m_pfnBegin ) (*m_pfnBegin)(); }
- void Process( T &item ) { (*m_pfnProcess)( item ); }
- void End() { if ( m_pfnEnd ) (*m_pfnEnd)(); }
-
-protected:
- void (*m_pfnProcess)( T & );
- void (*m_pfnBegin)();
- void (*m_pfnEnd)();
-};
-
-template <typename T, class OBJECT_TYPE, class FUNCTION_CLASS = OBJECT_TYPE >
-class CMemberFuncJobItemProcessor : public CJobItemProcessor<T>
-{
-public:
- void Init( OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( T & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL )
- {
- m_pObject = pObject;
- m_pfnProcess = pfnProcess;
- m_pfnBegin = pfnBegin;
- m_pfnEnd = pfnEnd;
- }
-
- void Begin() { if ( m_pfnBegin ) ((*m_pObject).*m_pfnBegin)(); }
- void Process( T &item ) { ((*m_pObject).*m_pfnProcess)( item ); }
- void End() { if ( m_pfnEnd ) ((*m_pObject).*m_pfnEnd)(); }
-
-protected:
- OBJECT_TYPE *m_pObject;
- void (FUNCTION_CLASS::*m_pfnProcess)( T & );
- void (FUNCTION_CLASS::*m_pfnBegin)();
- void (FUNCTION_CLASS::*m_pfnEnd)();
-};
-
-template <typename ITEM_TYPE, class ITEM_PROCESSOR_TYPE>
-class CParallelProcessor
-{
-public:
- CParallelProcessor( const char *pszDescription )
- {
- m_pItems = m_pLimit= 0;
- m_szDescription = pszDescription;
- }
-
- void Run( ITEM_TYPE *pItems, unsigned nItems, int nMaxParallel = INT_MAX, IThreadPool *pThreadPool = NULL )
- {
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "Run %s %d", m_szDescription, nItems );
-
- if ( nItems == 0 )
- return;
-
- if ( !pThreadPool )
- {
- pThreadPool = g_pThreadPool;
- }
-
- m_pItems = pItems;
- m_pLimit = pItems + nItems;
-
- int nJobs = nItems - 1;
-
- if ( nJobs > nMaxParallel )
- {
- nJobs = nMaxParallel;
- }
-
- if (! pThreadPool ) // only possible on linux
- {
- DoExecute( );
- return;
- }
-
- int nThreads = pThreadPool->NumThreads();
- if ( nJobs > nThreads )
- {
- nJobs = nThreads;
- }
-
- if ( nJobs > 1 )
- {
- CJob **jobs = (CJob **)stackalloc( nJobs * sizeof(CJob **) );
- int i = nJobs;
-
- while( i-- )
- {
- jobs[i] = pThreadPool->QueueCall( this, &CParallelProcessor<ITEM_TYPE, ITEM_PROCESSOR_TYPE>::DoExecute );
- jobs[i]->SetDescription( m_szDescription );
- }
-
- DoExecute();
-
- for ( i = 0; i < nJobs; i++ )
- {
- jobs[i]->Abort(); // will either abort ones that never got a thread, or noop on ones that did
- jobs[i]->Release();
- }
- }
- else
- {
- DoExecute();
- }
- }
-
- ITEM_PROCESSOR_TYPE m_ItemProcessor;
-
-private:
- void DoExecute()
- {
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription );
-
- if ( m_pItems < m_pLimit )
- {
- m_ItemProcessor.Begin();
-
- ITEM_TYPE *pLimit = m_pLimit;
-
- for (;;)
- {
- ITEM_TYPE *pCurrent = m_pItems++;
- if ( pCurrent < pLimit )
- {
- m_ItemProcessor.Process( *pCurrent );
- }
- else
- {
- break;
- }
- }
-
- m_ItemProcessor.End();
- }
- }
- CInterlockedPtr<ITEM_TYPE> m_pItems;
- ITEM_TYPE * m_pLimit;
- const char * m_szDescription;
-};
-
-template <typename ITEM_TYPE>
-inline void ParallelProcess( const char *pszDescription, ITEM_TYPE *pItems, unsigned nItems, void (*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
-{
- CParallelProcessor<ITEM_TYPE, CFuncJobItemProcessor<ITEM_TYPE> > processor( pszDescription );
- processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd );
- processor.Run( pItems, nItems, nMaxParallel );
-
-}
-
-template <typename ITEM_TYPE, typename OBJECT_TYPE, typename FUNCTION_CLASS >
-inline void ParallelProcess( const char *pszDescription, ITEM_TYPE *pItems, unsigned nItems, OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( ITEM_TYPE & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
-{
- CParallelProcessor<ITEM_TYPE, CMemberFuncJobItemProcessor<ITEM_TYPE, OBJECT_TYPE, FUNCTION_CLASS> > processor( pszDescription );
- processor.m_ItemProcessor.Init( pObject, pfnProcess, pfnBegin, pfnEnd );
- processor.Run( pItems, nItems, nMaxParallel );
-}
-
-// Parallel Process that lets you specify threadpool
-template <typename ITEM_TYPE>
-inline void ParallelProcess( const char *pszDescription, IThreadPool *pPool, ITEM_TYPE *pItems, unsigned nItems, void (*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
-{
- CParallelProcessor<ITEM_TYPE, CFuncJobItemProcessor<ITEM_TYPE> > processor( pszDescription );
- processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd );
- processor.Run( pItems, nItems, nMaxParallel, pPool );
-}
-
-
-template <class ITEM_PROCESSOR_TYPE>
-class CParallelLoopProcessor
-{
-public:
- CParallelLoopProcessor( const char *pszDescription )
- {
- m_lIndex = m_lLimit= 0;
- m_nActive = 0;
- m_szDescription = pszDescription;
- }
-
- void Run( long lBegin, long nItems, int nMaxParallel = INT_MAX )
- {
- if ( nItems )
- {
- m_lIndex = lBegin;
- m_lLimit = lBegin + nItems;
- int i = g_pThreadPool->NumIdleThreads();
-
- if ( nMaxParallel < i)
- {
- i = nMaxParallel;
- }
-
- while( i-- )
- {
- ++m_nActive;
- ThreadExecute( this, &CParallelLoopProcessor<ITEM_PROCESSOR_TYPE>::DoExecute )->Release();
- }
-
- ++m_nActive;
- DoExecute();
-
- while ( m_nActive )
- {
- ThreadPause();
- }
- }
- }
-
- ITEM_PROCESSOR_TYPE m_ItemProcessor;
-
-private:
- void DoExecute()
- {
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription );
-
- m_ItemProcessor.Begin();
-
- long lLimit = m_lLimit;
-
- for (;;)
- {
- long lIndex = m_lIndex ++;
- if ( lIndex < lLimit )
- {
- m_ItemProcessor.Process( lIndex );
- }
- else
- {
- break;
- }
- }
-
- m_ItemProcessor.End();
-
- --m_nActive;
- }
- CInterlockedInt m_lIndex;
- long m_lLimit;
- CInterlockedInt m_nActive;
- const char * m_szDescription;
-};
-
-inline void ParallelLoopProcess( const char *szDescription, long lBegin, unsigned nItems, void (*pfnProcess)( long const & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
-{
- CParallelLoopProcessor< CFuncJobItemProcessor< long const > > processor( szDescription );
- processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd );
- processor.Run( lBegin, nItems, nMaxParallel );
-
-}
-
-template < typename OBJECT_TYPE, typename FUNCTION_CLASS >
-inline void ParallelLoopProcess( const char *szDescription, long lBegin, unsigned nItems, OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( long const & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
-{
- CParallelLoopProcessor< CMemberFuncJobItemProcessor<long const, OBJECT_TYPE, FUNCTION_CLASS> > processor( szDescription );
- processor.m_ItemProcessor.Init( pObject, pfnProcess, pfnBegin, pfnEnd );
- processor.Run( lBegin, nItems, nMaxParallel );
-}
-
-
-template <class Derived>
-class CParallelProcessorBase
-{
-protected:
- typedef CParallelProcessorBase<Derived> ThisParallelProcessorBase_t;
- typedef Derived ThisParallelProcessorDerived_t;
-
-public:
- CParallelProcessorBase()
- {
- m_nActive = 0;
- m_szDescription = NULL;
- }
- void SetDescription( const char *pszDescription )
- {
- m_szDescription = pszDescription;
- }
-
-protected:
- void Run( int nMaxParallel = INT_MAX, int threadOverride = -1 )
- {
- int i = g_pThreadPool->NumIdleThreads();
-
- if ( nMaxParallel < i)
- {
- i = nMaxParallel;
- }
-
- while( i -- > 0 )
- {
- if ( threadOverride == -1 || i == threadOverride - 1 )
- {
- ++ m_nActive;
- ThreadExecute( this, &ThisParallelProcessorBase_t::DoExecute )->Release();
- }
- }
-
- if ( threadOverride == -1 || threadOverride == 0 )
- {
- ++ m_nActive;
- DoExecute();
- }
-
- while ( m_nActive )
- {
- ThreadPause();
- }
- }
-
-protected:
- void OnBegin() {}
- bool OnProcess() { return false; }
- void OnEnd() {}
-
-private:
- void DoExecute()
- {
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription );
-
- static_cast<Derived *>( this )->OnBegin();
-
- while ( static_cast<Derived *>( this )->OnProcess() )
- continue;
-
- static_cast<Derived *>(this)->OnEnd();
-
- -- m_nActive;
- }
-
- CInterlockedInt m_nActive;
- const char * m_szDescription;
-};
-
-
-
-
-//-----------------------------------------------------------------------------
-// Raw thread launching
-//-----------------------------------------------------------------------------
-
-inline unsigned FunctorExecuteThread( void *pParam )
-{
- CFunctor *pFunctor = (CFunctor *)pParam;
- (*pFunctor)();
- pFunctor->Release();
- return 0;
-}
-
-inline ThreadHandle_t ThreadExecuteSoloImpl( CFunctor *pFunctor, const char *pszName = NULL )
-{
- ThreadHandle_t hThread;
- ThreadId_t threadId;
- hThread = CreateSimpleThread( FunctorExecuteThread, pFunctor, &threadId );
- if ( pszName )
- {
- ThreadSetDebugName( threadId, pszName );
- }
- return hThread;
-}
-
-inline ThreadHandle_t ThreadExecuteSolo( CJob *pJob ) { return ThreadExecuteSoloImpl( CreateFunctor( pJob, &CJob::Execute ), pJob->Describe() ); }
-
-template <typename T1>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1 ), pszName ); }
-
-template <typename T1, typename T2>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2 ), pszName ); }
-
-template <typename T1, typename T2, typename T3>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6, a7 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
-inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6, a7, a8 ), pszName ); }
-
-template <typename T1, typename T2>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2 ), pszName ); }
-
-template <typename T1, typename T2, typename T3>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7 ), pszName ); }
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
-inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7, a8 ), pszName ); }
-
-//-----------------------------------------------------------------------------
-
-inline bool IThreadPool::YieldWait( CThreadEvent &event, unsigned timeout )
-{
- CThreadEvent *pEvent = &event;
- return ( YieldWait( &pEvent, 1, true, timeout ) != TW_TIMEOUT );
-}
-
-inline bool IThreadPool::YieldWait( CJob *pJob, unsigned timeout )
-{
- return ( YieldWait( &pJob, 1, true, timeout ) != TW_TIMEOUT );
-}
-
-//-----------------------------------------------------------------------------
-
-inline JobStatus_t CJob::Execute()
-{
- if ( IsFinished() )
- {
- return m_status;
- }
-
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status );
-
- AUTO_LOCK( m_mutex );
- AddRef();
-
- JobStatus_t result;
-
- switch ( m_status )
- {
- case JOB_STATUS_UNSERVICED:
- case JOB_STATUS_PENDING:
- {
- // Service it
- m_status = JOB_STATUS_INPROGRESS;
- result = m_status = DoExecute();
- DoCleanup();
- m_CompleteEvent.Set();
- break;
- }
-
- case JOB_STATUS_INPROGRESS:
- AssertMsg(0, "Mutex Should have protected use while processing");
- // fall through...
-
- case JOB_OK:
- case JOB_STATUS_ABORTED:
- result = m_status;
- break;
-
- default:
- AssertMsg( m_status < JOB_OK, "Unknown job state");
- result = m_status;
- }
-
- Release();
-
- return result;
-}
-
-
-//---------------------------------------------------------
-
-inline JobStatus_t CJob::TryExecute()
-{
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status );
-
- // TryLock() would only fail if another thread has entered
- // Execute() or Abort()
- if ( !IsFinished() && TryLock() )
- {
- // ...service the request
- Execute();
- Unlock();
- }
- return m_status;
-}
-
-//---------------------------------------------------------
-
-inline JobStatus_t CJob::Abort( bool bDiscard )
-{
- if ( IsFinished() )
- {
- return m_status;
- }
-
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status );
-
- AUTO_LOCK( m_mutex );
- AddRef();
-
- JobStatus_t result;
-
- switch ( m_status )
- {
- case JOB_STATUS_UNSERVICED:
- case JOB_STATUS_PENDING:
- {
- tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CJob::DoAbort" );
-
- result = m_status = DoAbort( bDiscard );
- if ( bDiscard )
- DoCleanup();
- m_CompleteEvent.Set();
- }
- break;
-
- case JOB_STATUS_ABORTED:
- case JOB_STATUS_INPROGRESS:
- case JOB_OK:
- result = m_status;
- break;
-
- default:
- AssertMsg( m_status < JOB_OK, "Unknown job state");
- result = m_status;
- }
-
- Release();
-
- return result;
-}
-
-//-----------------------------------------------------------------------------
-
-#endif // JOBTHREAD_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A utility for a discrete job-oriented worker thread.
+//
+// The class CThreadPool is both the job queue, and the
+// worker thread. Except when the main thread attempts to
+// synchronously execute a job, most of the inter-thread locking
+// on the queue.
+//
+// The queue threading model uses a manual reset event for optimal
+// throughput. Adding to the queue is guarded by a semaphore that
+// will block the inserting thread if the queue has overflown.
+// This prevents the worker thread from being starved out even if
+// not running at a higher priority than the master thread.
+//
+// The thread function waits for jobs, services jobs, and manages
+// communication between the worker and master threads. The nature
+// of the work is opaque to the Executer.
+//
+// CJob instances actually do the work. The base class
+// calls virtual methods for job primitives, so derivations don't
+// need to worry about threading models. All of the variants of
+// job and OS can be expressed in this hierarchy. Instances of
+// CJob are the items placed in the queue, and by
+// overriding the job primitives they are the manner by which
+// users of the Executer control the state of the job.
+//
+//=============================================================================
+
+#include <limits.h>
+#include "tier0/threadtools.h"
+#include "tier1/refcount.h"
+#include "tier1/utllinkedlist.h"
+#include "tier1/utlvector.h"
+#include "tier1/functors.h"
+#include "tier0/vprof_telemetry.h"
+
+#include "vstdlib/vstdlib.h"
+
+#ifndef JOBTHREAD_H
+#define JOBTHREAD_H
+
+#ifdef AddJob // windows.h print function collisions
+#undef AddJob
+#undef GetJob
+#endif
+
+#ifdef VSTDLIB_DLL_EXPORT
+#define JOB_INTERFACE DLL_EXPORT
+#define JOB_OVERLOAD DLL_GLOBAL_EXPORT
+#define JOB_CLASS DLL_CLASS_EXPORT
+#else
+#define JOB_INTERFACE DLL_IMPORT
+#define JOB_OVERLOAD DLL_GLOBAL_IMPORT
+#define JOB_CLASS DLL_CLASS_IMPORT
+#endif
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+
+class CJob;
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+enum JobStatusEnum_t
+{
+ // Use negative for errors
+ JOB_OK, // operation is successful
+ JOB_STATUS_PENDING, // file is properly queued, waiting for service
+ JOB_STATUS_INPROGRESS, // file is being accessed
+ JOB_STATUS_ABORTED, // file was aborted by caller
+ JOB_STATUS_UNSERVICED, // file is not yet queued
+};
+
+typedef int JobStatus_t;
+
+enum JobFlags_t
+{
+ JF_IO = ( 1 << 0 ), // The job primarily blocks on IO or hardware
+ JF_BOOST_THREAD = ( 1 << 1 ), // Up the thread priority to max allowed while processing task
+ JF_SERIAL = ( 1 << 2 ), // Job cannot be executed out of order relative to other "strict" jobs
+ JF_QUEUE = ( 1 << 3 ), // Queue it, even if not an IO job
+};
+
+enum JobPriority_t
+{
+ JP_LOW,
+ JP_NORMAL,
+ JP_HIGH
+};
+
+#define TP_MAX_POOL_THREADS 64
+struct ThreadPoolStartParams_t
+{
+ ThreadPoolStartParams_t( bool bIOThreads = false, unsigned nThreads = -1, int *pAffinities = NULL, ThreeState_t fDistribute = TRS_NONE, unsigned nStackSize = -1, int iThreadPriority = SHRT_MIN )
+ : bIOThreads( bIOThreads ), nThreads( nThreads ), fDistribute( fDistribute ), nStackSize( nStackSize ), iThreadPriority( iThreadPriority ), nThreadsMax( -1 )
+ {
+ bExecOnThreadPoolThreadsOnly = false;
+
+ bUseAffinityTable = ( pAffinities != NULL ) && ( fDistribute == TRS_TRUE ) && ( nThreads != -1 );
+ if ( bUseAffinityTable )
+ {
+ // user supplied an optional 1:1 affinity mapping to override normal distribute behavior
+ nThreads = MIN( TP_MAX_POOL_THREADS, nThreads );
+ for ( unsigned int i = 0; i < nThreads; i++ )
+ {
+ iAffinityTable[i] = pAffinities[i];
+ }
+ }
+ }
+
+ int nThreads;
+ int nThreadsMax;
+ ThreeState_t fDistribute;
+ int nStackSize;
+ int iThreadPriority;
+ int iAffinityTable[TP_MAX_POOL_THREADS];
+
+ bool bIOThreads : 1;
+ bool bUseAffinityTable : 1;
+ bool bExecOnThreadPoolThreadsOnly : 1;
+};
+
+//-----------------------------------------------------------------------------
+//
+// IThreadPool
+//
+//-----------------------------------------------------------------------------
+
+typedef bool (*JobFilter_t)( CJob * );
+
+//---------------------------------------------------------
+// Messages supported through the CallWorker() method
+//---------------------------------------------------------
+enum ThreadPoolMessages_t
+{
+ TPM_EXIT, // Exit the thread
+ TPM_SUSPEND, // Suspend after next operation
+ TPM_RUNFUNCTOR, // Run functor, reply when done.
+};
+
+//---------------------------------------------------------
+
+abstract_class IThreadPool : public IRefCounted
+{
+public:
+ virtual ~IThreadPool() {};
+
+ //-----------------------------------------------------
+ // Thread functions
+ //-----------------------------------------------------
+ virtual bool Start( const ThreadPoolStartParams_t &startParams = ThreadPoolStartParams_t() ) = 0;
+ virtual bool Stop( int timeout = TT_INFINITE ) = 0;
+
+ //-----------------------------------------------------
+ // Functions for any thread
+ //-----------------------------------------------------
+ virtual unsigned GetJobCount() = 0;
+ virtual int NumThreads() = 0;
+ virtual int NumIdleThreads() = 0;
+
+ //-----------------------------------------------------
+ // Pause/resume processing jobs
+ //-----------------------------------------------------
+ virtual int SuspendExecution() = 0;
+ virtual int ResumeExecution() = 0;
+
+ //-----------------------------------------------------
+ // Offer the current thread to the pool
+ //-----------------------------------------------------
+ virtual int YieldWait( CThreadEvent **pEvents, int nEvents, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) = 0;
+ virtual int YieldWait( CJob **, int nJobs, bool bWaitAll = true, unsigned timeout = TT_INFINITE ) = 0;
+ virtual void Yield( unsigned timeout ) = 0;
+
+ bool YieldWait( CThreadEvent &event, unsigned timeout = TT_INFINITE );
+ bool YieldWait( CJob *, unsigned timeout = TT_INFINITE );
+
+ //-----------------------------------------------------
+ // Add a native job to the queue (master thread)
+ //-----------------------------------------------------
+ virtual void AddJob( CJob * ) = 0;
+
+ //-----------------------------------------------------
+ // All threads execute pFunctor asap. Thread will either wake up
+ // and execute or execute pFunctor right after completing current job and
+ // before looking for another job.
+ //-----------------------------------------------------
+ virtual void ExecuteHighPriorityFunctor( CFunctor *pFunctor ) = 0;
+
+ //-----------------------------------------------------
+ // Add an function object to the queue (master thread)
+ //-----------------------------------------------------
+ virtual void AddFunctor( CFunctor *pFunctor, CJob **ppJob = NULL, const char *pszDescription = NULL, unsigned flags = 0 ) { AddFunctorInternal( RetAddRef( pFunctor ), ppJob, pszDescription, flags ); }
+
+ //-----------------------------------------------------
+ // Change the priority of an active job
+ //-----------------------------------------------------
+ virtual void ChangePriority( CJob *p, JobPriority_t priority ) = 0;
+
+ //-----------------------------------------------------
+ // Bulk job manipulation (blocking)
+ //-----------------------------------------------------
+ int ExecuteAll( JobFilter_t pfnFilter = NULL ) { return ExecuteToPriority( JP_LOW, pfnFilter ); }
+ virtual int ExecuteToPriority( JobPriority_t toPriority, JobFilter_t pfnFilter = NULL ) = 0;
+ virtual int AbortAll() = 0;
+
+ //-----------------------------------------------------
+ virtual void Reserved1() = 0;
+
+ //-----------------------------------------------------
+ // Add an arbitrary call to the queue (master thread)
+ //
+ // Avert thy eyes! Imagine rather:
+ //
+ // CJob *AddCall( <function>, [args1, [arg2,]...]
+ // CJob *AddCall( <object>, <function>, [args1, [arg2,]...]
+ // CJob *AddRefCall( <object>, <function>, [args1, [arg2,]...]
+ // CJob *QueueCall( <function>, [args1, [arg2,]...]
+ // CJob *QueueCall( <object>, <function>, [args1, [arg2,]...]
+ //-----------------------------------------------------
+
+ #define DEFINE_NONMEMBER_ADD_CALL(N) \
+ template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *AddCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ if ( !NumIdleThreads() ) \
+ { \
+ pJob = GetDummyJob(); \
+ FunctorDirectCall( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
+ } \
+ \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_MEMBER_ADD_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ if ( !NumIdleThreads() ) \
+ { \
+ pJob = GetDummyJob(); \
+ FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
+ } \
+ \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_CONST_MEMBER_ADD_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *AddCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ if ( !NumIdleThreads() ) \
+ { \
+ pJob = GetDummyJob(); \
+ FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
+ } \
+ \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_REF_COUNTING_MEMBER_ADD_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ if ( !NumIdleThreads() ) \
+ { \
+ pJob = GetDummyJob(); \
+ FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
+ } \
+ \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *AddRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ if ( !NumIdleThreads() ) \
+ { \
+ pJob = GetDummyJob(); \
+ FunctorDirectCall( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob ); \
+ } \
+ \
+ return pJob; \
+ }
+
+ //-----------------------------------------------------------------------------
+
+ #define DEFINE_NONMEMBER_QUEUE_CALL(N) \
+ template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ AddFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_CONST_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *QueueCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ AddFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
+ return pJob; \
+ }
+
+ //-------------------------------------
+
+ #define DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
+ CJob *QueueRefCall(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ CJob *pJob; \
+ AddFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ), &pJob, NULL, JF_QUEUE ); \
+ \
+ return pJob; \
+ }
+
+ FUNC_GENERATE_ALL( DEFINE_NONMEMBER_ADD_CALL );
+ FUNC_GENERATE_ALL( DEFINE_MEMBER_ADD_CALL );
+ FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_ADD_CALL );
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_ADD_CALL );
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL );
+ FUNC_GENERATE_ALL( DEFINE_NONMEMBER_QUEUE_CALL );
+ FUNC_GENERATE_ALL( DEFINE_MEMBER_QUEUE_CALL );
+ FUNC_GENERATE_ALL( DEFINE_CONST_MEMBER_QUEUE_CALL );
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL );
+ FUNC_GENERATE_ALL( DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL );
+
+ #undef DEFINE_NONMEMBER_ADD_CALL
+ #undef DEFINE_MEMBER_ADD_CALL
+ #undef DEFINE_CONST_MEMBER_ADD_CALL
+ #undef DEFINE_REF_COUNTING_MEMBER_ADD_CALL
+ #undef DEFINE_REF_COUNTING_CONST_MEMBER_ADD_CALL
+ #undef DEFINE_NONMEMBER_QUEUE_CALL
+ #undef DEFINE_MEMBER_QUEUE_CALL
+ #undef DEFINE_CONST_MEMBER_QUEUE_CALL
+ #undef DEFINE_REF_COUNTING_MEMBER_QUEUE_CALL
+ #undef DEFINE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL
+
+private:
+ virtual void AddFunctorInternal( CFunctor *, CJob ** = NULL, const char *pszDescription = NULL, unsigned flags = 0 ) = 0;
+
+ //-----------------------------------------------------
+ // Services for internal use by job instances
+ //-----------------------------------------------------
+ friend class CJob;
+
+ virtual CJob *GetDummyJob() = 0;
+
+public:
+ virtual void Distribute( bool bDistribute = true, int *pAffinityTable = NULL ) = 0;
+
+ virtual bool Start( const ThreadPoolStartParams_t &startParams, const char *pszNameOverride ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+
+JOB_INTERFACE IThreadPool *CreateThreadPool();
+JOB_INTERFACE void DestroyThreadPool( IThreadPool *pPool );
+
+//-------------------------------------
+
+JOB_INTERFACE void RunThreadPoolTests();
+
+//-----------------------------------------------------------------------------
+
+JOB_INTERFACE IThreadPool *g_pThreadPool;
+
+//-----------------------------------------------------------------------------
+// Class to combine the metadata for an operation and the ability to perform
+// the operation. Meant for inheritance. All functions inline, defers to executor
+//-----------------------------------------------------------------------------
+DECLARE_POINTER_HANDLE( ThreadPoolData_t );
+#define JOB_NO_DATA ((ThreadPoolData_t)-1)
+
+class CJob : public CRefCounted1<IRefCounted, CRefCountServiceMT>
+{
+public:
+ CJob( JobPriority_t priority = JP_NORMAL )
+ : m_status( JOB_STATUS_UNSERVICED ),
+ m_ThreadPoolData( JOB_NO_DATA ),
+ m_priority( priority ),
+ m_flags( 0 ),
+ m_pThreadPool( NULL ),
+ m_CompleteEvent( true ),
+ m_iServicingThread( -1 )
+ {
+ m_szDescription[ 0 ] = 0;
+ }
+
+ //-----------------------------------------------------
+ // Priority (not thread safe)
+ //-----------------------------------------------------
+ void SetPriority( JobPriority_t priority ) { m_priority = priority; }
+ JobPriority_t GetPriority() const { return m_priority; }
+
+ //-----------------------------------------------------
+
+ void SetFlags( unsigned flags ) { m_flags = flags; }
+ unsigned GetFlags() const { return m_flags; }
+
+ //-----------------------------------------------------
+
+ void SetServiceThread( int iServicingThread ) { m_iServicingThread = (char)iServicingThread; }
+ int GetServiceThread() const { return m_iServicingThread; }
+ void ClearServiceThread() { m_iServicingThread = -1; }
+
+ //-----------------------------------------------------
+ // Fast queries
+ //-----------------------------------------------------
+ bool Executed() const { return ( m_status == JOB_OK ); }
+ bool CanExecute() const { return ( m_status == JOB_STATUS_PENDING || m_status == JOB_STATUS_UNSERVICED ); }
+ bool IsFinished() const { return ( m_status != JOB_STATUS_PENDING && m_status != JOB_STATUS_INPROGRESS && m_status != JOB_STATUS_UNSERVICED ); }
+ JobStatus_t GetStatus() const { return m_status; }
+
+ /// Slam the status to a particular value. This is named "slam" instead of "set,"
+ /// to warn you that it should only be used in unusual situations. Otherwise, the
+ /// job manager really should manage the status for you, and you should not manhandle it.
+ void SlamStatus(JobStatus_t s) { m_status = s; }
+
+ //-----------------------------------------------------
+ // Try to acquire ownership (to satisfy). If you take the lock, you must either execute or abort.
+ //-----------------------------------------------------
+ bool TryLock() { return m_mutex.TryLock(); }
+ void Lock() { m_mutex.Lock(); }
+ void Unlock() { m_mutex.Unlock(); }
+
+ //-----------------------------------------------------
+ // Thread event support (safe for NULL this to simplify code )
+ //-----------------------------------------------------
+ bool WaitForFinish( uint32 dwTimeout = TT_INFINITE ) { if (!this) return true; return ( !IsFinished() ) ? g_pThreadPool->YieldWait( this, dwTimeout ) : true; }
+ bool WaitForFinishAndRelease( uint32 dwTimeout = TT_INFINITE ) { if (!this) return true; bool bResult = WaitForFinish( dwTimeout); Release(); return bResult; }
+ CThreadEvent *AccessEvent() { return &m_CompleteEvent; }
+
+ //-----------------------------------------------------
+ // Perform the job
+ //-----------------------------------------------------
+ JobStatus_t Execute();
+ JobStatus_t TryExecute();
+ JobStatus_t ExecuteAndRelease() { JobStatus_t status = Execute(); Release(); return status; }
+ JobStatus_t TryExecuteAndRelease() { JobStatus_t status = TryExecute(); Release(); return status; }
+
+ //-----------------------------------------------------
+ // Terminate the job, discard if partially or wholly fulfilled
+ //-----------------------------------------------------
+ JobStatus_t Abort( bool bDiscard = true );
+
+ virtual char const *Describe() { return m_szDescription[ 0 ] ? m_szDescription : "Job"; }
+ virtual void SetDescription( const char *pszDescription )
+ {
+ if( pszDescription )
+ {
+ Q_strncpy( m_szDescription, pszDescription, sizeof( m_szDescription ) );
+ }
+ else
+ {
+ m_szDescription[ 0 ] = 0;
+ }
+ }
+
+private:
+ //-----------------------------------------------------
+ friend class CThreadPool;
+
+ JobStatus_t m_status;
+ JobPriority_t m_priority;
+ CThreadMutex m_mutex;
+ unsigned char m_flags;
+ char m_iServicingThread;
+ short m_reserved;
+ ThreadPoolData_t m_ThreadPoolData;
+ IThreadPool * m_pThreadPool;
+ CThreadEvent m_CompleteEvent;
+ char m_szDescription[ 32 ];
+
+private:
+ //-----------------------------------------------------
+ CJob( const CJob &fromRequest );
+ void operator=(const CJob &fromRequest );
+
+ virtual JobStatus_t DoExecute() = 0;
+ virtual JobStatus_t DoAbort( bool bDiscard ) { return JOB_STATUS_ABORTED; }
+ virtual void DoCleanup() {}
+};
+
+//-----------------------------------------------------------------------------
+
+class CFunctorJob : public CJob
+{
+public:
+ CFunctorJob( CFunctor *pFunctor, const char *pszDescription = NULL )
+ : m_pFunctor( pFunctor )
+ {
+ if ( pszDescription )
+ {
+ Q_strncpy( m_szDescription, pszDescription, sizeof(m_szDescription) );
+ }
+ else
+ {
+ m_szDescription[0] = 0;
+ }
+ }
+
+ virtual JobStatus_t DoExecute()
+ {
+ (*m_pFunctor)();
+ return JOB_OK;
+ }
+
+ const char *Describe()
+ {
+ return m_szDescription;
+ }
+
+private:
+ CRefPtr<CFunctor> m_pFunctor;
+ char m_szDescription[16];
+};
+
+//-----------------------------------------------------------------------------
+// Utility for managing multiple jobs
+//-----------------------------------------------------------------------------
+
+class CJobSet
+{
+public:
+ CJobSet( CJob *pJob = NULL )
+ {
+ if ( pJob )
+ {
+ m_jobs.AddToTail( pJob );
+ }
+ }
+
+ CJobSet( CJob **ppJobs, int nJobs )
+ {
+ if ( ppJobs )
+ {
+ m_jobs.AddMultipleToTail( nJobs, ppJobs );
+ }
+ }
+
+ ~CJobSet()
+ {
+ for ( int i = 0; i < m_jobs.Count(); i++ )
+ {
+ m_jobs[i]->Release();
+ }
+ }
+
+ void operator+=( CJob *pJob )
+ {
+ m_jobs.AddToTail( pJob );
+ }
+
+ void operator-=( CJob *pJob )
+ {
+ m_jobs.FindAndRemove( pJob );
+ }
+
+ void Execute( bool bRelease = true )
+ {
+ for ( int i = 0; i < m_jobs.Count(); i++ )
+ {
+ m_jobs[i]->Execute();
+ if ( bRelease )
+ {
+ m_jobs[i]->Release();
+ }
+ }
+
+ if ( bRelease )
+ {
+ m_jobs.RemoveAll();
+ }
+ }
+
+ void Abort( bool bRelease = true )
+ {
+ for ( int i = 0; i < m_jobs.Count(); i++ )
+ {
+ m_jobs[i]->Abort();
+ if ( bRelease )
+ {
+ m_jobs[i]->Release();
+ }
+ }
+
+ if ( bRelease )
+ {
+ m_jobs.RemoveAll();
+ }
+ }
+
+ void WaitForFinish( bool bRelease = true )
+ {
+ for ( int i = 0; i < m_jobs.Count(); i++ )
+ {
+ m_jobs[i]->WaitForFinish();
+ if ( bRelease )
+ {
+ m_jobs[i]->Release();
+ }
+ }
+
+ if ( bRelease )
+ {
+ m_jobs.RemoveAll();
+ }
+ }
+
+ void WaitForFinish( IThreadPool *pPool, bool bRelease = true )
+ {
+ pPool->YieldWait( m_jobs.Base(), m_jobs.Count() );
+
+ if ( bRelease )
+ {
+ for ( int i = 0; i < m_jobs.Count(); i++ )
+ {
+ m_jobs[i]->Release();
+ }
+
+ m_jobs.RemoveAll();
+ }
+ }
+
+private:
+ CUtlVectorFixed<CJob *, 16> m_jobs;
+};
+
+//-----------------------------------------------------------------------------
+// Job helpers
+//-----------------------------------------------------------------------------
+
+#define ThreadExecute g_pThreadPool->QueueCall
+#define ThreadExecuteRef g_pThreadPool->QueueRefCall
+
+#define BeginExecuteParallel() do { CJobSet jobSet
+#define EndExecuteParallel() jobSet.WaitForFinish( g_pThreadPool ); } while (0)
+
+#define ExecuteParallel jobSet += g_pThreadPool->QueueCall
+#define ExecuteRefParallel jobSet += g_pThreadPool->QueueCallRef
+
+
+//-----------------------------------------------------------------------------
+// Work splitting: array split, best when cost per item is roughly equal
+//-----------------------------------------------------------------------------
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389)
+#pragma warning(disable:4018)
+#pragma warning(disable:4701)
+#endif
+
+#define DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL(N) \
+ template <typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N, typename ITERTYPE1, typename ITERTYPE2> \
+ void IterRangeParallel(FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_ADDL_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ const int MAX_THREADS = 16; \
+ int nIdle = g_pThreadPool->NumIdleThreads(); \
+ ITERTYPE1 range = to - from; \
+ int nThreads = MIN( nIdle + 1, range ); \
+ if ( nThreads > MAX_THREADS ) \
+ { \
+ nThreads = MAX_THREADS; \
+ } \
+ if ( nThreads < 2 ) \
+ { \
+ FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ ITERTYPE1 nIncrement = range / nThreads; \
+ \
+ CJobSet jobSet; \
+ while ( --nThreads ) \
+ { \
+ ITERTYPE2 thisTo = from + nIncrement; \
+ jobSet += g_pThreadPool->AddCall( pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ from = thisTo; \
+ } \
+ FunctorDirectCall( pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ jobSet.WaitForFinish( g_pThreadPool ); \
+ } \
+ \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_NON_MEMBER_ITER_RANGE_PARALLEL );
+
+#define DEFINE_MEMBER_ITER_RANGE_PARALLEL(N) \
+ template <typename OBJECT_TYPE, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N, typename ITERTYPE1, typename ITERTYPE2> \
+ void IterRangeParallel(OBJECT_TYPE *pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( ITERTYPE1, ITERTYPE2 FUNC_ADDL_TEMPLATE_FUNC_PARAMS_##N ), ITERTYPE1 from, ITERTYPE2 to FUNC_ARG_FORMAL_PARAMS_##N ) \
+ { \
+ const int MAX_THREADS = 16; \
+ int nIdle = g_pThreadPool->NumIdleThreads(); \
+ ITERTYPE1 range = to - from; \
+ int nThreads = MIN( nIdle + 1, range ); \
+ if ( nThreads > MAX_THREADS ) \
+ { \
+ nThreads = MAX_THREADS; \
+ } \
+ if ( nThreads < 2 ) \
+ { \
+ FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ } \
+ else \
+ { \
+ ITERTYPE1 nIncrement = range / nThreads; \
+ \
+ CJobSet jobSet; \
+ while ( --nThreads ) \
+ { \
+ ITERTYPE2 thisTo = from + nIncrement; \
+ jobSet += g_pThreadPool->AddCall( pObject, pfnProxied, from, thisTo FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ from = thisTo; \
+ } \
+ FunctorDirectCall( pObject, pfnProxied, from, to FUNC_FUNCTOR_CALL_ARGS_##N ); \
+ jobSet.WaitForFinish( g_pThreadPool ); \
+ } \
+ \
+ }
+
+FUNC_GENERATE_ALL( DEFINE_MEMBER_ITER_RANGE_PARALLEL );
+
+//-----------------------------------------------------------------------------
+// Work splitting: competitive, best when cost per item varies a lot
+//-----------------------------------------------------------------------------
+
+template <typename T>
+class CJobItemProcessor
+{
+public:
+ typedef T ItemType_t;
+ void Begin() {}
+ // void Process( ItemType_t & ) {}
+ void End() {}
+};
+
+template <typename T>
+class CFuncJobItemProcessor : public CJobItemProcessor<T>
+{
+public:
+ void Init(void (*pfnProcess)( T & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL )
+ {
+ m_pfnProcess = pfnProcess;
+ m_pfnBegin = pfnBegin;
+ m_pfnEnd = pfnEnd;
+ }
+
+ //CFuncJobItemProcessor(OBJECT_TYPE_PTR pObject, void (FUNCTION_CLASS::*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL );
+ void Begin() { if ( m_pfnBegin ) (*m_pfnBegin)(); }
+ void Process( T &item ) { (*m_pfnProcess)( item ); }
+ void End() { if ( m_pfnEnd ) (*m_pfnEnd)(); }
+
+protected:
+ void (*m_pfnProcess)( T & );
+ void (*m_pfnBegin)();
+ void (*m_pfnEnd)();
+};
+
+template <typename T, class OBJECT_TYPE, class FUNCTION_CLASS = OBJECT_TYPE >
+class CMemberFuncJobItemProcessor : public CJobItemProcessor<T>
+{
+public:
+ void Init( OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( T & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL )
+ {
+ m_pObject = pObject;
+ m_pfnProcess = pfnProcess;
+ m_pfnBegin = pfnBegin;
+ m_pfnEnd = pfnEnd;
+ }
+
+ void Begin() { if ( m_pfnBegin ) ((*m_pObject).*m_pfnBegin)(); }
+ void Process( T &item ) { ((*m_pObject).*m_pfnProcess)( item ); }
+ void End() { if ( m_pfnEnd ) ((*m_pObject).*m_pfnEnd)(); }
+
+protected:
+ OBJECT_TYPE *m_pObject;
+ void (FUNCTION_CLASS::*m_pfnProcess)( T & );
+ void (FUNCTION_CLASS::*m_pfnBegin)();
+ void (FUNCTION_CLASS::*m_pfnEnd)();
+};
+
+template <typename ITEM_TYPE, class ITEM_PROCESSOR_TYPE>
+class CParallelProcessor
+{
+public:
+ CParallelProcessor( const char *pszDescription )
+ {
+ m_pItems = m_pLimit= 0;
+ m_szDescription = pszDescription;
+ }
+
+ void Run( ITEM_TYPE *pItems, unsigned nItems, int nMaxParallel = INT_MAX, IThreadPool *pThreadPool = NULL )
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "Run %s %d", m_szDescription, nItems );
+
+ if ( nItems == 0 )
+ return;
+
+ if ( !pThreadPool )
+ {
+ pThreadPool = g_pThreadPool;
+ }
+
+ m_pItems = pItems;
+ m_pLimit = pItems + nItems;
+
+ int nJobs = nItems - 1;
+
+ if ( nJobs > nMaxParallel )
+ {
+ nJobs = nMaxParallel;
+ }
+
+ if (! pThreadPool ) // only possible on linux
+ {
+ DoExecute( );
+ return;
+ }
+
+ int nThreads = pThreadPool->NumThreads();
+ if ( nJobs > nThreads )
+ {
+ nJobs = nThreads;
+ }
+
+ if ( nJobs > 1 )
+ {
+ CJob **jobs = (CJob **)stackalloc( nJobs * sizeof(CJob **) );
+ int i = nJobs;
+
+ while( i-- )
+ {
+ jobs[i] = pThreadPool->QueueCall( this, &CParallelProcessor<ITEM_TYPE, ITEM_PROCESSOR_TYPE>::DoExecute );
+ jobs[i]->SetDescription( m_szDescription );
+ }
+
+ DoExecute();
+
+ for ( i = 0; i < nJobs; i++ )
+ {
+ jobs[i]->Abort(); // will either abort ones that never got a thread, or noop on ones that did
+ jobs[i]->Release();
+ }
+ }
+ else
+ {
+ DoExecute();
+ }
+ }
+
+ ITEM_PROCESSOR_TYPE m_ItemProcessor;
+
+private:
+ void DoExecute()
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription );
+
+ if ( m_pItems < m_pLimit )
+ {
+ m_ItemProcessor.Begin();
+
+ ITEM_TYPE *pLimit = m_pLimit;
+
+ for (;;)
+ {
+ ITEM_TYPE *pCurrent = m_pItems++;
+ if ( pCurrent < pLimit )
+ {
+ m_ItemProcessor.Process( *pCurrent );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ m_ItemProcessor.End();
+ }
+ }
+ CInterlockedPtr<ITEM_TYPE> m_pItems;
+ ITEM_TYPE * m_pLimit;
+ const char * m_szDescription;
+};
+
+template <typename ITEM_TYPE>
+inline void ParallelProcess( const char *pszDescription, ITEM_TYPE *pItems, unsigned nItems, void (*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
+{
+ CParallelProcessor<ITEM_TYPE, CFuncJobItemProcessor<ITEM_TYPE> > processor( pszDescription );
+ processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd );
+ processor.Run( pItems, nItems, nMaxParallel );
+
+}
+
+template <typename ITEM_TYPE, typename OBJECT_TYPE, typename FUNCTION_CLASS >
+inline void ParallelProcess( const char *pszDescription, ITEM_TYPE *pItems, unsigned nItems, OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( ITEM_TYPE & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
+{
+ CParallelProcessor<ITEM_TYPE, CMemberFuncJobItemProcessor<ITEM_TYPE, OBJECT_TYPE, FUNCTION_CLASS> > processor( pszDescription );
+ processor.m_ItemProcessor.Init( pObject, pfnProcess, pfnBegin, pfnEnd );
+ processor.Run( pItems, nItems, nMaxParallel );
+}
+
+// Parallel Process that lets you specify threadpool
+template <typename ITEM_TYPE>
+inline void ParallelProcess( const char *pszDescription, IThreadPool *pPool, ITEM_TYPE *pItems, unsigned nItems, void (*pfnProcess)( ITEM_TYPE & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
+{
+ CParallelProcessor<ITEM_TYPE, CFuncJobItemProcessor<ITEM_TYPE> > processor( pszDescription );
+ processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd );
+ processor.Run( pItems, nItems, nMaxParallel, pPool );
+}
+
+
+template <class ITEM_PROCESSOR_TYPE>
+class CParallelLoopProcessor
+{
+public:
+ CParallelLoopProcessor( const char *pszDescription )
+ {
+ m_lIndex = m_lLimit= 0;
+ m_nActive = 0;
+ m_szDescription = pszDescription;
+ }
+
+ void Run( long lBegin, long nItems, int nMaxParallel = INT_MAX )
+ {
+ if ( nItems )
+ {
+ m_lIndex = lBegin;
+ m_lLimit = lBegin + nItems;
+ int i = g_pThreadPool->NumIdleThreads();
+
+ if ( nMaxParallel < i)
+ {
+ i = nMaxParallel;
+ }
+
+ while( i-- )
+ {
+ ++m_nActive;
+ ThreadExecute( this, &CParallelLoopProcessor<ITEM_PROCESSOR_TYPE>::DoExecute )->Release();
+ }
+
+ ++m_nActive;
+ DoExecute();
+
+ while ( m_nActive )
+ {
+ ThreadPause();
+ }
+ }
+ }
+
+ ITEM_PROCESSOR_TYPE m_ItemProcessor;
+
+private:
+ void DoExecute()
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription );
+
+ m_ItemProcessor.Begin();
+
+ long lLimit = m_lLimit;
+
+ for (;;)
+ {
+ long lIndex = m_lIndex ++;
+ if ( lIndex < lLimit )
+ {
+ m_ItemProcessor.Process( lIndex );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ m_ItemProcessor.End();
+
+ --m_nActive;
+ }
+ CInterlockedInt m_lIndex;
+ long m_lLimit;
+ CInterlockedInt m_nActive;
+ const char * m_szDescription;
+};
+
+inline void ParallelLoopProcess( const char *szDescription, long lBegin, unsigned nItems, void (*pfnProcess)( long const & ), void (*pfnBegin)() = NULL, void (*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
+{
+ CParallelLoopProcessor< CFuncJobItemProcessor< long const > > processor( szDescription );
+ processor.m_ItemProcessor.Init( pfnProcess, pfnBegin, pfnEnd );
+ processor.Run( lBegin, nItems, nMaxParallel );
+
+}
+
+template < typename OBJECT_TYPE, typename FUNCTION_CLASS >
+inline void ParallelLoopProcess( const char *szDescription, long lBegin, unsigned nItems, OBJECT_TYPE *pObject, void (FUNCTION_CLASS::*pfnProcess)( long const & ), void (FUNCTION_CLASS::*pfnBegin)() = NULL, void (FUNCTION_CLASS::*pfnEnd)() = NULL, int nMaxParallel = INT_MAX )
+{
+ CParallelLoopProcessor< CMemberFuncJobItemProcessor<long const, OBJECT_TYPE, FUNCTION_CLASS> > processor( szDescription );
+ processor.m_ItemProcessor.Init( pObject, pfnProcess, pfnBegin, pfnEnd );
+ processor.Run( lBegin, nItems, nMaxParallel );
+}
+
+
+template <class Derived>
+class CParallelProcessorBase
+{
+protected:
+ typedef CParallelProcessorBase<Derived> ThisParallelProcessorBase_t;
+ typedef Derived ThisParallelProcessorDerived_t;
+
+public:
+ CParallelProcessorBase()
+ {
+ m_nActive = 0;
+ m_szDescription = NULL;
+ }
+ void SetDescription( const char *pszDescription )
+ {
+ m_szDescription = pszDescription;
+ }
+
+protected:
+ void Run( int nMaxParallel = INT_MAX, int threadOverride = -1 )
+ {
+ int i = g_pThreadPool->NumIdleThreads();
+
+ if ( nMaxParallel < i)
+ {
+ i = nMaxParallel;
+ }
+
+ while( i -- > 0 )
+ {
+ if ( threadOverride == -1 || i == threadOverride - 1 )
+ {
+ ++ m_nActive;
+ ThreadExecute( this, &ThisParallelProcessorBase_t::DoExecute )->Release();
+ }
+ }
+
+ if ( threadOverride == -1 || threadOverride == 0 )
+ {
+ ++ m_nActive;
+ DoExecute();
+ }
+
+ while ( m_nActive )
+ {
+ ThreadPause();
+ }
+ }
+
+protected:
+ void OnBegin() {}
+ bool OnProcess() { return false; }
+ void OnEnd() {}
+
+private:
+ void DoExecute()
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "DoExecute %s", m_szDescription );
+
+ static_cast<Derived *>( this )->OnBegin();
+
+ while ( static_cast<Derived *>( this )->OnProcess() )
+ continue;
+
+ static_cast<Derived *>(this)->OnEnd();
+
+ -- m_nActive;
+ }
+
+ CInterlockedInt m_nActive;
+ const char * m_szDescription;
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Raw thread launching
+//-----------------------------------------------------------------------------
+
+inline unsigned FunctorExecuteThread( void *pParam )
+{
+ CFunctor *pFunctor = (CFunctor *)pParam;
+ (*pFunctor)();
+ pFunctor->Release();
+ return 0;
+}
+
+inline ThreadHandle_t ThreadExecuteSoloImpl( CFunctor *pFunctor, const char *pszName = NULL )
+{
+ ThreadHandle_t hThread;
+ ThreadId_t threadId;
+ hThread = CreateSimpleThread( FunctorExecuteThread, pFunctor, &threadId );
+ if ( pszName )
+ {
+ ThreadSetDebugName( threadId, pszName );
+ }
+ return hThread;
+}
+
+inline ThreadHandle_t ThreadExecuteSolo( CJob *pJob ) { return ThreadExecuteSoloImpl( CreateFunctor( pJob, &CJob::Execute ), pJob->Describe() ); }
+
+template <typename T1>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1 ), pszName ); }
+
+template <typename T1, typename T2>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2 ), pszName ); }
+
+template <typename T1, typename T2, typename T3>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6, a7 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+inline ThreadHandle_t ThreadExecuteSolo( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8 ) { return ThreadExecuteSoloImpl( CreateFunctor( a1, a2, a3, a4, a5, a6, a7, a8 ), pszName ); }
+
+template <typename T1, typename T2>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2 ), pszName ); }
+
+template <typename T1, typename T2, typename T3>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7 ), pszName ); }
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
+inline ThreadHandle_t ThreadExecuteSoloRef( const char *pszName, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8 ) { return ThreadExecuteSoloImpl( CreateRefCountingFunctor(a1, a2, a3, a4, a5, a6, a7, a8 ), pszName ); }
+
+//-----------------------------------------------------------------------------
+
+inline bool IThreadPool::YieldWait( CThreadEvent &event, unsigned timeout )
+{
+ CThreadEvent *pEvent = &event;
+ return ( YieldWait( &pEvent, 1, true, timeout ) != TW_TIMEOUT );
+}
+
+inline bool IThreadPool::YieldWait( CJob *pJob, unsigned timeout )
+{
+ return ( YieldWait( &pJob, 1, true, timeout ) != TW_TIMEOUT );
+}
+
+//-----------------------------------------------------------------------------
+
+inline JobStatus_t CJob::Execute()
+{
+ if ( IsFinished() )
+ {
+ return m_status;
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status );
+
+ AUTO_LOCK( m_mutex );
+ AddRef();
+
+ JobStatus_t result;
+
+ switch ( m_status )
+ {
+ case JOB_STATUS_UNSERVICED:
+ case JOB_STATUS_PENDING:
+ {
+ // Service it
+ m_status = JOB_STATUS_INPROGRESS;
+ result = m_status = DoExecute();
+ DoCleanup();
+ m_CompleteEvent.Set();
+ break;
+ }
+
+ case JOB_STATUS_INPROGRESS:
+ AssertMsg(0, "Mutex Should have protected use while processing");
+ // fall through...
+
+ case JOB_OK:
+ case JOB_STATUS_ABORTED:
+ result = m_status;
+ break;
+
+ default:
+ AssertMsg( m_status < JOB_OK, "Unknown job state");
+ result = m_status;
+ }
+
+ Release();
+
+ return result;
+}
+
+
+//---------------------------------------------------------
+
+inline JobStatus_t CJob::TryExecute()
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status );
+
+ // TryLock() would only fail if another thread has entered
+ // Execute() or Abort()
+ if ( !IsFinished() && TryLock() )
+ {
+ // ...service the request
+ Execute();
+ Unlock();
+ }
+ return m_status;
+}
+
+//---------------------------------------------------------
+
+inline JobStatus_t CJob::Abort( bool bDiscard )
+{
+ if ( IsFinished() )
+ {
+ return m_status;
+ }
+
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %s %d", __FUNCTION__, Describe(), m_status );
+
+ AUTO_LOCK( m_mutex );
+ AddRef();
+
+ JobStatus_t result;
+
+ switch ( m_status )
+ {
+ case JOB_STATUS_UNSERVICED:
+ case JOB_STATUS_PENDING:
+ {
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "CJob::DoAbort" );
+
+ result = m_status = DoAbort( bDiscard );
+ if ( bDiscard )
+ DoCleanup();
+ m_CompleteEvent.Set();
+ }
+ break;
+
+ case JOB_STATUS_ABORTED:
+ case JOB_STATUS_INPROGRESS:
+ case JOB_OK:
+ result = m_status;
+ break;
+
+ default:
+ AssertMsg( m_status < JOB_OK, "Unknown job state");
+ result = m_status;
+ }
+
+ Release();
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // JOBTHREAD_H
diff --git a/mp/src/public/vstdlib/osversion.h b/mp/src/public/vstdlib/osversion.h
index 52be4216..ecc68ae5 100644
--- a/mp/src/public/vstdlib/osversion.h
+++ b/mp/src/public/vstdlib/osversion.h
@@ -1,60 +1,60 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $Date: $
-//
-//-----------------------------------------------------------------------------
-// $Log: $
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#ifndef OSVERSION_H
-#define OSVERSION_H
-#pragma once
-
-#include "vstdlib/vstdlib.h"
-
-// OS types we know about
-// Must be in ascending capability order, we use this for min OS requirements
-enum EOSType
-{
- k_eOSUnknown = -1,
- k_eMacOSUnknown = -102,
- k_eMacOS104 = -101,
- k_eMacOS105 = -100,
- k_eMacOS1058 = -99,
- k_eMacOS106 = -95,
- k_eMacOS1063 = -94,
- k_eMacOS107 = -90,
- // k_eMacOSMax = -1
- k_eLinuxUnknown = -203,
- k_eLinux22 = -202,
- k_eLinux24 = -201,
- k_eLinux26 = -200,
- // k_eLinuxMax = -103
- k_eWinUnknown = 0,
- k_eWin311 = 1,
- k_eWin95,
- k_eWin98,
- k_eWinME,
- k_eWinNT,
- k_eWin2000,
- k_eWinXP,
- k_eWin2003,
- k_eWinVista,
- k_eWindows7,
- k_eWin2008,
- k_eWinMAX,
- k_eOSTypeMax = k_eWinMAX + 11 // win types + other ifdef'd types
-};
-
-VSTDLIB_INTERFACE const char *GetNameFromOSType( EOSType eOSType );
-VSTDLIB_INTERFACE const char *GetOSDetailString( char *pchOutBuf, int cchOutBuf );
-VSTDLIB_INTERFACE EOSType GetOSType();
-VSTDLIB_INTERFACE bool OSTypesAreCompatible( EOSType eOSTypeDetected, EOSType eOSTypeRequired );
-VSTDLIB_INTERFACE const char *GetPlatformName( bool *pbIs64Bit );
-
-#endif // OSVERSION_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OSVERSION_H
+#define OSVERSION_H
+#pragma once
+
+#include "vstdlib/vstdlib.h"
+
+// OS types we know about
+// Must be in ascending capability order, we use this for min OS requirements
+enum EOSType
+{
+ k_eOSUnknown = -1,
+ k_eMacOSUnknown = -102,
+ k_eMacOS104 = -101,
+ k_eMacOS105 = -100,
+ k_eMacOS1058 = -99,
+ k_eMacOS106 = -95,
+ k_eMacOS1063 = -94,
+ k_eMacOS107 = -90,
+ // k_eMacOSMax = -1
+ k_eLinuxUnknown = -203,
+ k_eLinux22 = -202,
+ k_eLinux24 = -201,
+ k_eLinux26 = -200,
+ // k_eLinuxMax = -103
+ k_eWinUnknown = 0,
+ k_eWin311 = 1,
+ k_eWin95,
+ k_eWin98,
+ k_eWinME,
+ k_eWinNT,
+ k_eWin2000,
+ k_eWinXP,
+ k_eWin2003,
+ k_eWinVista,
+ k_eWindows7,
+ k_eWin2008,
+ k_eWinMAX,
+ k_eOSTypeMax = k_eWinMAX + 11 // win types + other ifdef'd types
+};
+
+VSTDLIB_INTERFACE const char *GetNameFromOSType( EOSType eOSType );
+VSTDLIB_INTERFACE const char *GetOSDetailString( char *pchOutBuf, int cchOutBuf );
+VSTDLIB_INTERFACE EOSType GetOSType();
+VSTDLIB_INTERFACE bool OSTypesAreCompatible( EOSType eOSTypeDetected, EOSType eOSTypeRequired );
+VSTDLIB_INTERFACE const char *GetPlatformName( bool *pbIs64Bit );
+
+#endif // OSVERSION_H
diff --git a/mp/src/public/vstdlib/pch_vstdlib.h b/mp/src/public/vstdlib/pch_vstdlib.h
index 72d70939..57242c41 100644
--- a/mp/src/public/vstdlib/pch_vstdlib.h
+++ b/mp/src/public/vstdlib/pch_vstdlib.h
@@ -1,51 +1,51 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// The copyright to the contents herein is the property of Valve, L.L.C.
-// The contents may be used and/or copied only with the written permission of
-// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
-// the agreement/contract under which the contents have been supplied.
-//
-// Purpose:
-//
-// $Workfile: $
-// $NoKeywords: $
-//=============================================================================
-
-
-#pragma warning(disable: 4514)
-
-// First include standard libraries
-#include <stdio.h>
-#include <ctype.h>
-#include <math.h>
-#include <malloc.h>
-#include <memory.h>
-#include <ctype.h>
-
-// Next, include public
-#include "tier0/basetypes.h"
-#include "tier0/dbg.h"
-#include "tier0/valobject.h"
-
-// Next, include vstdlib
-#include "vstdlib/vstdlib.h"
-#include "tier1/strtools.h"
-#include "vstdlib/random.h"
-#include "tier1/KeyValues.h"
-#include "tier1/utlmemory.h"
-#include "tier1/utlrbtree.h"
-#include "tier1/utlvector.h"
-#include "tier1/utllinkedlist.h"
-#include "tier1/utlmultilist.h"
-#include "tier1/utlsymbol.h"
-#include "tier0/icommandline.h"
-#include "tier1/netadr.h"
-#include "tier1/mempool.h"
-#include "tier1/utlbuffer.h"
-#include "tier1/utlstring.h"
-#include "tier1/utlmap.h"
-
-#include "tier0/memdbgon.h"
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The copyright to the contents herein is the property of Valve, L.L.C.
+// The contents may be used and/or copied only with the written permission of
+// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
+// the agreement/contract under which the contents have been supplied.
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================
+
+
+#pragma warning(disable: 4514)
+
+// First include standard libraries
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <malloc.h>
+#include <memory.h>
+#include <ctype.h>
+
+// Next, include public
+#include "tier0/basetypes.h"
+#include "tier0/dbg.h"
+#include "tier0/valobject.h"
+
+// Next, include vstdlib
+#include "vstdlib/vstdlib.h"
+#include "tier1/strtools.h"
+#include "vstdlib/random.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlmemory.h"
+#include "tier1/utlrbtree.h"
+#include "tier1/utlvector.h"
+#include "tier1/utllinkedlist.h"
+#include "tier1/utlmultilist.h"
+#include "tier1/utlsymbol.h"
+#include "tier0/icommandline.h"
+#include "tier1/netadr.h"
+#include "tier1/mempool.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/utlstring.h"
+#include "tier1/utlmap.h"
+
+#include "tier0/memdbgon.h"
+
+
+
diff --git a/mp/src/public/vstdlib/random.h b/mp/src/public/vstdlib/random.h
index 5c56eb12..88188031 100644
--- a/mp/src/public/vstdlib/random.h
+++ b/mp/src/public/vstdlib/random.h
@@ -1,111 +1,111 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Random number generator
-//
-// $Workfile: $
-// $NoKeywords: $
-//===========================================================================//
-
-#ifndef VSTDLIB_RANDOM_H
-#define VSTDLIB_RANDOM_H
-
-#include "vstdlib/vstdlib.h"
-#include "tier0/basetypes.h"
-#include "tier0/threadtools.h"
-#include "tier1/interface.h"
-
-#define NTAB 32
-
-#pragma warning(push)
-#pragma warning( disable:4251 )
-
-//-----------------------------------------------------------------------------
-// A generator of uniformly distributed random numbers
-//-----------------------------------------------------------------------------
-class IUniformRandomStream
-{
-public:
- // Sets the seed of the random number generator
- virtual void SetSeed( int iSeed ) = 0;
-
- // Generates random numbers
- virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ) = 0;
- virtual int RandomInt( int iMinVal, int iMaxVal ) = 0;
- virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ) = 0;
-};
-
-
-//-----------------------------------------------------------------------------
-// The standard generator of uniformly distributed random numbers
-//-----------------------------------------------------------------------------
-class VSTDLIB_CLASS CUniformRandomStream : public IUniformRandomStream
-{
-public:
- CUniformRandomStream();
-
- // Sets the seed of the random number generator
- virtual void SetSeed( int iSeed );
-
- // Generates random numbers
- virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f );
- virtual int RandomInt( int iMinVal, int iMaxVal );
- virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f );
-
-private:
- int GenerateRandomNumber();
-
- int m_idum;
- int m_iy;
- int m_iv[NTAB];
-
- CThreadFastMutex m_mutex;
-};
-
-
-//-----------------------------------------------------------------------------
-// A generator of gaussian distributed random numbers
-//-----------------------------------------------------------------------------
-class VSTDLIB_CLASS CGaussianRandomStream
-{
-public:
- // Passing in NULL will cause the gaussian stream to use the
- // installed global random number generator
- CGaussianRandomStream( IUniformRandomStream *pUniformStream = NULL );
-
- // Attaches to a random uniform stream
- void AttachToStream( IUniformRandomStream *pUniformStream = NULL );
-
- // Generates random numbers
- float RandomFloat( float flMean = 0.0f, float flStdDev = 1.0f );
-
-private:
- IUniformRandomStream *m_pUniformStream;
- bool m_bHaveValue;
- float m_flRandomValue;
-
- CThreadFastMutex m_mutex;
-};
-
-
-//-----------------------------------------------------------------------------
-// A couple of convenience functions to access the library's global uniform stream
-//-----------------------------------------------------------------------------
-VSTDLIB_INTERFACE void RandomSeed( int iSeed );
-VSTDLIB_INTERFACE float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f );
-VSTDLIB_INTERFACE float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f );
-VSTDLIB_INTERFACE int RandomInt( int iMinVal, int iMaxVal );
-VSTDLIB_INTERFACE float RandomGaussianFloat( float flMean = 0.0f, float flStdDev = 1.0f );
-
-
-//-----------------------------------------------------------------------------
-// Installs a global random number generator, which will affect the Random functions above
-//-----------------------------------------------------------------------------
-VSTDLIB_INTERFACE void InstallUniformRandomStream( IUniformRandomStream *pStream );
-
-
-#pragma warning(pop)
-
-#endif // VSTDLIB_RANDOM_H
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Random number generator
+//
+// $Workfile: $
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef VSTDLIB_RANDOM_H
+#define VSTDLIB_RANDOM_H
+
+#include "vstdlib/vstdlib.h"
+#include "tier0/basetypes.h"
+#include "tier0/threadtools.h"
+#include "tier1/interface.h"
+
+#define NTAB 32
+
+#pragma warning(push)
+#pragma warning( disable:4251 )
+
+//-----------------------------------------------------------------------------
+// A generator of uniformly distributed random numbers
+//-----------------------------------------------------------------------------
+class IUniformRandomStream
+{
+public:
+ // Sets the seed of the random number generator
+ virtual void SetSeed( int iSeed ) = 0;
+
+ // Generates random numbers
+ virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f ) = 0;
+ virtual int RandomInt( int iMinVal, int iMaxVal ) = 0;
+ virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// The standard generator of uniformly distributed random numbers
+//-----------------------------------------------------------------------------
+class VSTDLIB_CLASS CUniformRandomStream : public IUniformRandomStream
+{
+public:
+ CUniformRandomStream();
+
+ // Sets the seed of the random number generator
+ virtual void SetSeed( int iSeed );
+
+ // Generates random numbers
+ virtual float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f );
+ virtual int RandomInt( int iMinVal, int iMaxVal );
+ virtual float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f );
+
+private:
+ int GenerateRandomNumber();
+
+ int m_idum;
+ int m_iy;
+ int m_iv[NTAB];
+
+ CThreadFastMutex m_mutex;
+};
+
+
+//-----------------------------------------------------------------------------
+// A generator of gaussian distributed random numbers
+//-----------------------------------------------------------------------------
+class VSTDLIB_CLASS CGaussianRandomStream
+{
+public:
+ // Passing in NULL will cause the gaussian stream to use the
+ // installed global random number generator
+ CGaussianRandomStream( IUniformRandomStream *pUniformStream = NULL );
+
+ // Attaches to a random uniform stream
+ void AttachToStream( IUniformRandomStream *pUniformStream = NULL );
+
+ // Generates random numbers
+ float RandomFloat( float flMean = 0.0f, float flStdDev = 1.0f );
+
+private:
+ IUniformRandomStream *m_pUniformStream;
+ bool m_bHaveValue;
+ float m_flRandomValue;
+
+ CThreadFastMutex m_mutex;
+};
+
+
+//-----------------------------------------------------------------------------
+// A couple of convenience functions to access the library's global uniform stream
+//-----------------------------------------------------------------------------
+VSTDLIB_INTERFACE void RandomSeed( int iSeed );
+VSTDLIB_INTERFACE float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f );
+VSTDLIB_INTERFACE float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f );
+VSTDLIB_INTERFACE int RandomInt( int iMinVal, int iMaxVal );
+VSTDLIB_INTERFACE float RandomGaussianFloat( float flMean = 0.0f, float flStdDev = 1.0f );
+
+
+//-----------------------------------------------------------------------------
+// Installs a global random number generator, which will affect the Random functions above
+//-----------------------------------------------------------------------------
+VSTDLIB_INTERFACE void InstallUniformRandomStream( IUniformRandomStream *pStream );
+
+
+#pragma warning(pop)
+
+#endif // VSTDLIB_RANDOM_H
+
+
+
diff --git a/mp/src/public/vstdlib/vcover.h b/mp/src/public/vstdlib/vcover.h
index a705d776..156534c0 100644
--- a/mp/src/public/vstdlib/vcover.h
+++ b/mp/src/public/vstdlib/vcover.h
@@ -1,125 +1,125 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: A simple tool for coverage tests
-//
-//=============================================================================
-
-#ifndef VCOVER_H
-#define VCOVER_H
-
-#include "tier1/utlrbtree.h"
-#include "vstdlib.h"
-
-#if defined( _WIN32 )
-#pragma once
-#endif
-
-class CVCoverage
-{
-public:
- CVCoverage() :
- m_bActive( false ),
- m_depth( 0 ),
- m_token( 1 )
- {
- }
-
- bool IsActive() const
- {
- return m_bActive;
- }
-
- void SetActive( bool bActive )
- {
- Assert( bActive != m_bActive );
- m_bActive = bActive;
- if ( bActive )
- ++m_token;
- }
-
- void Begin()
- {
- ++m_depth;
- }
-
- void End()
- {
- --m_depth;
- }
-
- void Reset()
- {
- m_locations.RemoveAll();
- }
-
- bool ShouldCover( unsigned token ) const
- {
- return ( m_bActive && m_depth > 0 && token != m_token );
- }
-
- unsigned Cover( const char *pszFile, int line )
- {
- Location_t location = { pszFile, line };
-
- m_locations.Insert( location );
-
- return m_token;
- }
-
- void Report()
- {
- for ( int i = m_locations.FirstInorder(); i != m_locations.InvalidIndex(); i = m_locations.NextInorder( i ) )
- {
- Msg( "%s(%d) :\n", m_locations[i].pszFile, m_locations[i].line );
- }
- }
-
-private:
- struct Location_t
- {
- const char *pszFile;
- int line;
-
- };
-
- class CLocationLess
- {
- public:
- CLocationLess( int ignored ) {}
- bool operator!() { return false; }
-
- bool operator()( const Location_t &lhs, const Location_t &rhs ) const
- {
- if ( lhs.line < rhs.line )
- {
- return true;
- }
-
- return CaselessStringLessThan( lhs.pszFile, rhs.pszFile );
- }
- };
-
- bool m_bActive;
- int m_depth;
- unsigned m_token;
-
- CUtlRBTree< Location_t, unsigned short, CLocationLess > m_locations;
-};
-
-VSTDLIB_INTERFACE CVCoverage g_VCoverage;
-
-#ifdef VCOVER_ENABLED
-#define VCOVER() \
- do \
- { \
- static token; \
- if ( g_VCoverage.ShouldCover( token ) ) \
- { \
- token = g_VCoverage.Cover( __FILE__, __LINE__ ); \
- } \
- } while( 0 )
-#else
-#define VCOVER() ((void)0)
-#endif
-
-#endif // VCOVER_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A simple tool for coverage tests
+//
+//=============================================================================
+
+#ifndef VCOVER_H
+#define VCOVER_H
+
+#include "tier1/utlrbtree.h"
+#include "vstdlib.h"
+
+#if defined( _WIN32 )
+#pragma once
+#endif
+
+class CVCoverage
+{
+public:
+ CVCoverage() :
+ m_bActive( false ),
+ m_depth( 0 ),
+ m_token( 1 )
+ {
+ }
+
+ bool IsActive() const
+ {
+ return m_bActive;
+ }
+
+ void SetActive( bool bActive )
+ {
+ Assert( bActive != m_bActive );
+ m_bActive = bActive;
+ if ( bActive )
+ ++m_token;
+ }
+
+ void Begin()
+ {
+ ++m_depth;
+ }
+
+ void End()
+ {
+ --m_depth;
+ }
+
+ void Reset()
+ {
+ m_locations.RemoveAll();
+ }
+
+ bool ShouldCover( unsigned token ) const
+ {
+ return ( m_bActive && m_depth > 0 && token != m_token );
+ }
+
+ unsigned Cover( const char *pszFile, int line )
+ {
+ Location_t location = { pszFile, line };
+
+ m_locations.Insert( location );
+
+ return m_token;
+ }
+
+ void Report()
+ {
+ for ( int i = m_locations.FirstInorder(); i != m_locations.InvalidIndex(); i = m_locations.NextInorder( i ) )
+ {
+ Msg( "%s(%d) :\n", m_locations[i].pszFile, m_locations[i].line );
+ }
+ }
+
+private:
+ struct Location_t
+ {
+ const char *pszFile;
+ int line;
+
+ };
+
+ class CLocationLess
+ {
+ public:
+ CLocationLess( int ignored ) {}
+ bool operator!() { return false; }
+
+ bool operator()( const Location_t &lhs, const Location_t &rhs ) const
+ {
+ if ( lhs.line < rhs.line )
+ {
+ return true;
+ }
+
+ return CaselessStringLessThan( lhs.pszFile, rhs.pszFile );
+ }
+ };
+
+ bool m_bActive;
+ int m_depth;
+ unsigned m_token;
+
+ CUtlRBTree< Location_t, unsigned short, CLocationLess > m_locations;
+};
+
+VSTDLIB_INTERFACE CVCoverage g_VCoverage;
+
+#ifdef VCOVER_ENABLED
+#define VCOVER() \
+ do \
+ { \
+ static token; \
+ if ( g_VCoverage.ShouldCover( token ) ) \
+ { \
+ token = g_VCoverage.Cover( __FILE__, __LINE__ ); \
+ } \
+ } while( 0 )
+#else
+#define VCOVER() ((void)0)
+#endif
+
+#endif // VCOVER_H
diff --git a/mp/src/public/vstdlib/vstdlib.h b/mp/src/public/vstdlib/vstdlib.h
index 94b71a6e..4e3a7f89 100644
--- a/mp/src/public/vstdlib/vstdlib.h
+++ b/mp/src/public/vstdlib/vstdlib.h
@@ -1,33 +1,33 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-#ifndef VSTDLIB_H
-#define VSTDLIB_H
-
-#ifdef _WIN32
-#pragma once
-#endif
-
-#include "tier0/platform.h"
-
-//-----------------------------------------------------------------------------
-// dll export stuff
-//-----------------------------------------------------------------------------
-#ifdef VSTDLIB_DLL_EXPORT
-#define VSTDLIB_INTERFACE DLL_EXPORT
-#define VSTDLIB_OVERLOAD DLL_GLOBAL_EXPORT
-#define VSTDLIB_CLASS DLL_CLASS_EXPORT
-#define VSTDLIB_GLOBAL DLL_GLOBAL_EXPORT
-#else
-#define VSTDLIB_INTERFACE DLL_IMPORT
-#define VSTDLIB_OVERLOAD DLL_GLOBAL_IMPORT
-#define VSTDLIB_CLASS DLL_CLASS_IMPORT
-#define VSTDLIB_GLOBAL DLL_GLOBAL_IMPORT
-#endif
-
-#endif // VSTDLIB_H
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef VSTDLIB_H
+#define VSTDLIB_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+
+//-----------------------------------------------------------------------------
+// dll export stuff
+//-----------------------------------------------------------------------------
+#ifdef VSTDLIB_DLL_EXPORT
+#define VSTDLIB_INTERFACE DLL_EXPORT
+#define VSTDLIB_OVERLOAD DLL_GLOBAL_EXPORT
+#define VSTDLIB_CLASS DLL_CLASS_EXPORT
+#define VSTDLIB_GLOBAL DLL_GLOBAL_EXPORT
+#else
+#define VSTDLIB_INTERFACE DLL_IMPORT
+#define VSTDLIB_OVERLOAD DLL_GLOBAL_IMPORT
+#define VSTDLIB_CLASS DLL_CLASS_IMPORT
+#define VSTDLIB_GLOBAL DLL_GLOBAL_IMPORT
+#endif
+
+#endif // VSTDLIB_H