diff options
| author | Narendra Umate <[email protected]> | 2013-12-02 23:36:05 -0800 |
|---|---|---|
| committer | Narendra Umate <[email protected]> | 2013-12-02 23:36:05 -0800 |
| commit | 8737f191f3b59f001a77bf6c08091109211c1c9f (patch) | |
| tree | dbbf05c004d9b026f2c1f23f06600fe0add82c36 /mp/src/public/vstdlib | |
| parent | Update .gitignore. (diff) | |
| parent | Make .xcconfigs text files too. (diff) | |
| download | source-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.h | 96 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/coroutine.h | 138 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/cvar.h | 50 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/iprocessutils.h | 128 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/jobthread.h | 2688 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/osversion.h | 120 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/pch_vstdlib.h | 102 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/random.h | 222 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/vcover.h | 250 | ||||
| -rw-r--r-- | mp/src/public/vstdlib/vstdlib.h | 66 |
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 |