mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-19 20:16:10 +08:00
Add schemasystem (#215)
Update CUtlMemoryPool*, CUtlSymbol*, CUtlTSHash, CThreadSpinRWLock, CThreadFastMutex (now replaced by CThreadSpinMutex) Implemented some missing ThreadInterlocked* functions
This commit is contained in:
@ -23,6 +23,7 @@
|
||||
#define FENTCLASS_UNK009 (1 << 9)
|
||||
#define FENTCLASS_FORCE_WORLDGROUPID (1 << 10) // Forces worldgroupid to be 1 on created entities
|
||||
|
||||
class CSchemaClassInfo;
|
||||
class CEntityClass;
|
||||
class CEntityIdentity;
|
||||
class ServerClass;
|
||||
@ -44,7 +45,7 @@ public:
|
||||
const char* m_pszDescription;
|
||||
CEntityClass *m_pClass;
|
||||
CEntityClassInfo *m_pBaseClassInfo;
|
||||
void* m_pSchemaBinding;
|
||||
CSchemaClassInfo* m_pSchemaBinding;
|
||||
datamap_t* m_pDataDescMap;
|
||||
datamap_t* m_pPredDescMap;
|
||||
};
|
||||
@ -76,6 +77,11 @@ class CEntityClass
|
||||
};
|
||||
|
||||
public:
|
||||
inline CSchemaClassInfo *GetSchemaBinding() const
|
||||
{
|
||||
return m_pClassInfo->m_pSchemaBinding;
|
||||
}
|
||||
|
||||
inline datamap_t *GetDataDescMap() const
|
||||
{
|
||||
return m_pClassInfo->m_pDataDescMap;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "tier1/utlsymbollarge.h"
|
||||
#include "tier1/utlstring.h"
|
||||
#include "datamap.h"
|
||||
#include "schemasystem/schematypes.h"
|
||||
|
||||
class CEntityIdentity;
|
||||
class CEntityComponentHelper;
|
||||
@ -22,7 +23,7 @@ struct ComponentUnserializerKeyNamesChunk_t
|
||||
|
||||
struct ComponentUnserializerFieldInfo_t
|
||||
{
|
||||
void* m_pSchemaEnum;
|
||||
CSchemaEnumInfo* m_pSchemaEnum;
|
||||
const char* m_pKeyName;
|
||||
|
||||
uint16 m_nOffset;
|
||||
@ -72,9 +73,9 @@ struct EntComponentInfo_t
|
||||
class CEntityComponentHelper
|
||||
{
|
||||
public:
|
||||
virtual void Schema_DynamicBinding(void**) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> Schema_DynamicBinding() = 0;
|
||||
virtual void Finalize() = 0;
|
||||
virtual void GetSchemaBinding(void**) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> GetSchemaBinding() = 0;
|
||||
virtual datamap_t* GetDataDescMap() = 0;
|
||||
virtual bool Allocate( CEntityIdentity* pEntity, void* pComponent ) = 0;
|
||||
virtual void Free( CEntityIdentity* pEntity, void* pComponent ) = 0;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "entity2/entitycomponent.h"
|
||||
#include "entity2/entityidentity.h"
|
||||
#include "variant.h"
|
||||
#include "schemasystem/schematypes.h"
|
||||
|
||||
class CEntityKeyValues;
|
||||
class CFieldPath;
|
||||
@ -77,7 +78,7 @@ public:
|
||||
virtual void ReloadPrivateScripts() = 0;
|
||||
virtual datamap_t* GetDataDescMap() = 0;
|
||||
virtual void unk201() = 0;
|
||||
virtual void Schema_DynamicBinding(void**) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> Schema_DynamicBinding() = 0;
|
||||
|
||||
public:
|
||||
inline CEntityHandle GetRefEHandle() const
|
||||
|
221
public/schemasystem/schemasystem.h
Normal file
221
public/schemasystem/schemasystem.h
Normal file
@ -0,0 +1,221 @@
|
||||
#ifndef SCHEMASYSTEM_H
|
||||
#define SCHEMASYSTEM_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/threadtools.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "tier1/utlstring.h"
|
||||
#include "tier1/UtlStringMap.h"
|
||||
#include "tier1/utltshash.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "appframework/IAppSystem.h"
|
||||
#include "schemasystem/schematypes.h"
|
||||
|
||||
class CBufferString;
|
||||
class CKeyValues3Context;
|
||||
struct ResourceManifestDesc_t;
|
||||
|
||||
enum SchemaTypeScope_t : uint8
|
||||
{
|
||||
SCHEMA_TYPESCOPE_GLOBAL = 0,
|
||||
SCHEMA_TYPESCOPE_LOCAL,
|
||||
SCHEMA_TYPESCOPE_DEFAULT,
|
||||
};
|
||||
|
||||
typedef void (*CompleteModuleRegistrationCallbackFn_t)(void*);
|
||||
|
||||
abstract_class ISchemaSystemTypeScope
|
||||
{
|
||||
public:
|
||||
virtual CSchemaClassInfo* InstallSchemaClassBinding( const char* pszModuleName, CSchemaClassInfo* pClassInfo ) = 0;
|
||||
virtual CSchemaEnumInfo* InstallSchemaEnumBinding( const char* pszModuleName, CSchemaEnumInfo* pEnumInfo ) = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> FindDeclaredClass( const char* pszClassName ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaEnumInfo> FindDeclaredEnum( const char* pszEnumName ) = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Builtin> FindBuiltinTypeByName( const char* pszBuiltinName ) = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Builtin> Type_Builtin( SchemaBuiltinType_t eBuiltinType ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Ptr> Type_Ptr( CSchemaType* pObjectType ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic> Type_Atomic( const char* pszAtomicName, uint16 nSize, uint8 nAlignment ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_T> Type_Atomic_T( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_CollectionOfT> Type_Atomic_CollectionOfT( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, uint16 nElementSize, CSchemaType* pTemplateType, SchemaAtomicManipulatorFn_t manipulator ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TF> Type_Atomic_TF( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, int nFuncPtrSize ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TT> Type_Atomic_TT( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, CSchemaType* pTemplateType2 ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TTF> Type_Atomic_TTF( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, CSchemaType* pTemplateType2, int nFuncPtrSize ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_I> Type_Atomic_I( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, int nInterger ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_DeclaredClass> Type_DeclaredClass( const char* pszClassName ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_DeclaredEnum> Type_DeclaredEnum( const char* pszEnumName ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_FixedArray> Type_FixedArray( CSchemaType* pElementType, int nElementCount, uint16 nElementSize, uint8 nElementAlignment ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_FixedArray> Type_FixedArray_Multidimensional( CSchemaType* pElementType, uint16 nElementSize, uint8 nElementAlignment, ... ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Bitfield> Type_Bitfield( int nSize ) = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic> FindType_Atomic( int nAtomicID ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_T> FindType_Atomic_T( int nAtomicID, CSchemaType* pTemplateType ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_CollectionOfT> FindType_Atomic_CollectionOfT( int nAtomicID, CSchemaType* pTemplateType, SchemaAtomicManipulatorFn_t manipulator ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TF> FindType_Atomic_TF( int nAtomicID, CSchemaType* pTemplateType, int nFuncPtrSize ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TT> FindType_Atomic_TT( int nAtomicID, CSchemaType* pTemplateType, CSchemaType* pTemplateType2 ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TTF> FindType_Atomic_TTF( int nAtomicID, CSchemaType* pTemplateType, CSchemaType* pTemplateType2, int nFuncPtrSize ) = 0;
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_I> FindType_Atomic_I( int nAtomicID, int nInteger ) = 0;
|
||||
|
||||
virtual CSchemaType_DeclaredClass* FindType_DeclaredClass( const char* pszClassName ) = 0;
|
||||
virtual CSchemaType_DeclaredEnum* FindType_DeclaredEnum( const char* pszEnumName ) = 0;
|
||||
|
||||
virtual CSchemaClassInfo* FindRawClassBinding( const char* pszClassName ) = 0;
|
||||
virtual CSchemaClassInfo* FindRawClassBinding( uint nClassID ) = 0;
|
||||
virtual CSchemaEnumInfo* FindRawEnumBinding( const char* pszEnumName ) = 0;
|
||||
virtual CSchemaEnumInfo* FindRawEnumBinding( uint nEnumID ) = 0;
|
||||
|
||||
virtual const char* GetScopeName() = 0;
|
||||
virtual bool IsGlobalScope() = 0;
|
||||
|
||||
virtual void MarkClassAsRequiringGlobalPromotion( const CSchemaClassInfo* pClassInfo ) = 0;
|
||||
virtual void MarkEnumAsRequiringGlobalPromotion( const CSchemaEnumInfo* pEnumInfo ) = 0;
|
||||
|
||||
virtual void ResolveAtomicInfoThreadsafe( const SchemaAtomicTypeInfo_t** ppAtomicInfo, const char* pszAtomicName, int nAtomicID ) = 0;
|
||||
virtual void ResolveEnumInfoThreadsafe( const CSchemaEnumInfo** pEnumInfo, const char* pszEnumName ) = 0;
|
||||
virtual void ResolveClassInfoThreadsafe( const CSchemaClassInfo** pClassInfo, const char* pszClassName ) = 0;
|
||||
};
|
||||
|
||||
class CSchemaSystemTypeScope : public ISchemaSystemTypeScope
|
||||
{
|
||||
public:
|
||||
char m_szScopeName[256];
|
||||
|
||||
CSchemaSystemTypeScope* m_pGlobalTypeScope;
|
||||
|
||||
bool m_bBuiltinTypesInitialized;
|
||||
CSchemaType_Builtin m_BuiltinTypes[SCHEMA_BUILTIN_COUNT];
|
||||
|
||||
CSchemaPtrMap<CSchemaType*, CSchemaType_Ptr*> m_Ptrs;
|
||||
CSchemaPtrMap<int, CSchemaType_Atomic*> m_Atomics;
|
||||
CSchemaPtrMap<AtomicTypeInfo_T_t, CSchemaType_Atomic_T*> m_AtomicsT;
|
||||
CSchemaPtrMap<AtomicTypeInfo_T_t, CSchemaType_Atomic_CollectionOfT*> m_AtomicsCollectionOfT;
|
||||
CSchemaPtrMap<AtomicTypeInfo_TF_t, CSchemaType_Atomic_TF*> m_AtomicsTF;
|
||||
CSchemaPtrMap<AtomicTypeInfo_TT_t, CSchemaType_Atomic_TT*> m_AtomicsTT;
|
||||
CSchemaPtrMap<AtomicTypeInfo_TTF_t, CSchemaType_Atomic_TTF*> m_AtomicsTTF;
|
||||
CSchemaPtrMap<AtomicTypeInfo_I_t, CSchemaType_Atomic_I*> m_AtomicsI;
|
||||
CSchemaPtrMap<uint, CSchemaType_DeclaredClass*> m_DeclaredClasses;
|
||||
CSchemaPtrMap<uint, CSchemaType_DeclaredEnum*> m_DeclaredEnums;
|
||||
CSchemaPtrMap<int, const SchemaAtomicTypeInfo_t*> m_AtomicInfos;
|
||||
CSchemaPtrMap<TypeAndCountInfo_t, CSchemaType_FixedArray*> m_FixedArrays;
|
||||
CSchemaPtrMap<int, CSchemaType_Bitfield*> m_Bitfields;
|
||||
|
||||
CUtlTSHash<CSchemaClassInfo*, 256, uint> m_ClassBindings;
|
||||
CUtlTSHash<CSchemaEnumInfo*, 256, uint> m_EnumBindings;
|
||||
};
|
||||
|
||||
#define SCHEMASYSTEM_INTERFACE_VERSION "SchemaSystem_001"
|
||||
|
||||
abstract_class ISchemaSystem : public IAppSystem
|
||||
{
|
||||
public:
|
||||
virtual CSchemaSystemTypeScope* GlobalTypeScope() = 0;
|
||||
virtual CSchemaSystemTypeScope* FindOrCreateTypeScopeForModule( const char* pszModuleName, const char** ppszBindingName = NULL ) = 0;
|
||||
virtual CSchemaSystemTypeScope* FindTypeScopeForModule( const char* pszModuleName, const char** ppszBindingName = NULL ) = 0;
|
||||
virtual CSchemaSystemTypeScope* GetTypeScopeForBinding( SchemaTypeScope_t eTypeScope, const char* pszModuleName, const char** ppszBindingName = NULL ) = 0;
|
||||
|
||||
virtual bool DefaultTypeScopeIsLocal() = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> FindClassByScopedName( const char* pszScopedName ) = 0;
|
||||
virtual void ScopedNameForClass( const CSchemaClassInfo* pClassInfo, CBufferString& scopedName ) = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaEnumInfo> FindEnumByScopedName( const char* pszScopedName ) = 0;
|
||||
virtual void ScopedNameForEnum( const CSchemaEnumInfo* pEnumInfo, CBufferString& scopedName ) = 0;
|
||||
|
||||
virtual void FindDescendentsOfClass( const CSchemaClassInfo* pClassInfo, int, CUtlVector<const CSchemaClassInfo*> *descendents, bool ) = 0;
|
||||
virtual void LoadSchemaDataForModules( const char** ppszModules, int nModules ) = 0;
|
||||
|
||||
virtual const char* GetClassModuleName( const CSchemaClassInfo* pClassInfo ) = 0;
|
||||
virtual const char* GetClassProjectName( const CSchemaClassInfo* pClassInfo ) = 0;
|
||||
|
||||
virtual const char* GetEnumModuleName( const CSchemaEnumInfo* pEnumInfo ) = 0;
|
||||
virtual const char* GetEnumProjectName( const CSchemaEnumInfo* pEnumInfo ) = 0;
|
||||
|
||||
virtual bool SchemaSystemIsReady() = 0;
|
||||
virtual void VerifySchemaBindingConsistency( bool ) = 0;
|
||||
virtual void CompleteModuleRegistration( const char* pszModuleName ) = 0;
|
||||
virtual void RegisterAtomicType( const SchemaAtomicTypeInfo_t* pAtomicType ) = 0;
|
||||
|
||||
virtual void PrintSchemaStats( const char* pszOptions ) = 0;
|
||||
virtual void PrintSchemaMetaStats( const char* pszOptions ) = 0;
|
||||
|
||||
virtual void RegisterAtomics( const char* pszModuleName, const char* pszProjectName, CSchemaType** ppSchemaTypes, int, SchemaAtomicTypeInfo_t** ppAtomicTypes ) = 0;
|
||||
virtual void RegisterEnums( const char* pszModuleName, const char* pszProjectName, CSchemaType** ppSchemaTypes, int, CSchemaEnumInfo** ppEnumInfos ) = 0;
|
||||
virtual bool RegisterClasses( const char* pszModuleName, const char* pszProjectName, CSchemaType** ppSchemaTypes, int, CSchemaClassInfo** ppClassInfos, CBufferString* pErrorStr ) = 0;
|
||||
virtual void ValidateClasses( CSchemaClassInfo** ppClassInfos ) = 0;
|
||||
|
||||
virtual bool ConvertOldIntrospectedResourceDataToKV3( void*, void*, void*, CKeyValues3Context*, const char* ) = 0;
|
||||
virtual void FindClassesByMeta( const char* pszMetaName, int, CUtlVector<const CSchemaClassInfo*> *classes ) = 0;
|
||||
|
||||
virtual void InstallCompleteModuleRegistrationCallback( CompleteModuleRegistrationCallbackFn_t pfnCallback, void* pArgument ) = 0;
|
||||
virtual void RemoveCompleteModuleRegistrationCallback( CompleteModuleRegistrationCallbackFn_t pfnCallback, void* pArgument ) = 0;
|
||||
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType_Builtin> GetSchemaBuiltinType( SchemaBuiltinType_t eBuiltinType ) = 0;
|
||||
|
||||
virtual ~ISchemaSystem() = 0;
|
||||
};
|
||||
|
||||
class CSchemaSystem : public ISchemaSystem
|
||||
{
|
||||
struct DetectedSchemaMismatch_t
|
||||
{
|
||||
CUtlString m_sBinding;
|
||||
CUtlString m_sMismatch;
|
||||
CUtlString m_sModule1;
|
||||
CUtlString m_sModule2;
|
||||
};
|
||||
|
||||
struct BindingsAddressRangeForModule_t
|
||||
{
|
||||
uintp m_minAddr;
|
||||
uintp m_maxAddr;
|
||||
};
|
||||
|
||||
struct CompleteModuleRegistrationCallback_t
|
||||
{
|
||||
CompleteModuleRegistrationCallbackFn_t m_pfnCallback;
|
||||
void* m_pArgument;
|
||||
};
|
||||
|
||||
public:
|
||||
CUtlVector<ResourceManifestDesc_t*> m_ResourceManifestDescs;
|
||||
int m_nNumConnections;
|
||||
CThreadFastMutex m_Mutex;
|
||||
|
||||
#ifdef CONVAR_WORK_FINISHED
|
||||
CConCommandMemberAccessor<CSchemaSystem> m_SchemaListBindings;
|
||||
CConCommandMemberAccessor<CSchemaSystem> m_SchemaAllListBindings;
|
||||
CConCommandMemberAccessor<CSchemaSystem> m_SchemaDumpBinding;
|
||||
CConCommandMemberAccessor<CSchemaSystem> m_SchemaDetailedClassLayout;
|
||||
CConCommandMemberAccessor<CSchemaSystem> m_SchemaStats;
|
||||
CConCommandMemberAccessor<CSchemaSystem> m_SchemaMetaStats;
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
uint8 pad[288];
|
||||
#else
|
||||
uint8 pad[384];
|
||||
#endif // _WIN32
|
||||
#endif // CONVAR_WORK_FINISHED
|
||||
|
||||
CUtlVector<void*> m_LoadedModules;
|
||||
CUtlVector<DetectedSchemaMismatch_t> m_DetectedSchemaMismatches;
|
||||
|
||||
bool m_bDefaultTypeScopeIsLocal;
|
||||
bool m_bSchemaSystemIsReady;
|
||||
|
||||
CUtlStringMap<CSchemaSystemTypeScope*> m_TypeScopes;
|
||||
CUtlStringMap<BindingsAddressRangeForModule_t> m_BindingsAddressRanges;
|
||||
|
||||
int m_nRegistrations;
|
||||
int m_nIgnored;
|
||||
int m_nRedundant;
|
||||
size_t m_nIgnoredBytes;
|
||||
|
||||
CUtlVector<CompleteModuleRegistrationCallback_t> m_CompleteModuleRegistrationCallbacks;
|
||||
};
|
||||
|
||||
#endif // SCHEMASYSTEM_H
|
427
public/schemasystem/schematypes.h
Normal file
427
public/schemasystem/schematypes.h
Normal file
@ -0,0 +1,427 @@
|
||||
#ifndef SCHEMATYPES_H
|
||||
#define SCHEMATYPES_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tier0/logging.h"
|
||||
#include "tier0/threadtools.h"
|
||||
#include "tier1/generichash.h"
|
||||
#include "tier1/utlmap.h"
|
||||
#include "tier1/utlstring.h"
|
||||
|
||||
class ISchemaSystemTypeScope;
|
||||
class CSchemaSystemTypeScope;
|
||||
class CSchemaClassInfo;
|
||||
class CSchemaEnumInfo;
|
||||
class CBufferString;
|
||||
struct SchemaAtomicTypeInfo_t;
|
||||
struct datamap_t;
|
||||
|
||||
enum SchemaClassFlags1_t
|
||||
{
|
||||
SCHEMA_CF1_HAS_VIRTUAL_MEMBERS = (1 << 0),
|
||||
SCHEMA_CF1_IS_ABSTRACT = (1 << 1),
|
||||
SCHEMA_CF1_HAS_TRIVIAL_CONSTRUCTOR = (1 << 2),
|
||||
SCHEMA_CF1_HAS_TRIVIAL_DESTRUCTOR = (1 << 3),
|
||||
SCHEMA_CF1_LIMITED_METADATA = (1 << 4),
|
||||
SCHEMA_CF1_INHERITANCE_DEPTH_CALCULATED = (1 << 5),
|
||||
SCHEMA_CF1_MODULE_LOCAL_TYPE_SCOPE = (1 << 6),
|
||||
SCHEMA_CF1_GLOBAL_TYPE_SCOPE = (1 << 7),
|
||||
SCHEMA_CF1_CONSTRUCT_ALLOWED = (1 << 8),
|
||||
SCHEMA_CF1_CONSTRUCT_DISALLOWED = (1 << 9),
|
||||
SCHEMA_CF1_INFO_TAG_MNetworkAssumeNotNetworkable = (1 << 10),
|
||||
SCHEMA_CF1_INFO_TAG_MNetworkNoBase = (1 << 11),
|
||||
SCHEMA_CF1_INFO_TAG_MIgnoreTypeScopeMetaChecks = (1 << 12),
|
||||
SCHEMA_CF1_INFO_TAG_MDisableDataDescValidation = (1 << 13),
|
||||
SCHEMA_CF1_INFO_TAG_MClassHasEntityLimitedDataDesc = (1 << 14),
|
||||
SCHEMA_CF1_INFO_TAG_MClassHasCustomAlignedNewDelete = (1 << 15),
|
||||
SCHEMA_CF1_UNK016 = (1 << 16),
|
||||
SCHEMA_CF1_UNK017 = (1 << 17),
|
||||
SCHEMA_CF1_INFO_TAG_MHasKV3TransferPolymorphicClassname = (1 << 18),
|
||||
};
|
||||
|
||||
enum SchemaClassFlags2_t {};
|
||||
|
||||
enum SchemaEnumFlags_t
|
||||
{
|
||||
SCHEMA_EF_IS_REGISTERED = (1 << 0),
|
||||
SCHEMA_EF_MODULE_LOCAL_TYPE_SCOPE = (1 << 1),
|
||||
SCHEMA_EF_GLOBAL_TYPE_SCOPE = (1 << 2),
|
||||
};
|
||||
|
||||
enum SchemaTypeCategory_t : uint8
|
||||
{
|
||||
SCHEMA_TYPE_BUILTIN = 0,
|
||||
SCHEMA_TYPE_PTR,
|
||||
SCHEMA_TYPE_BITFIELD,
|
||||
SCHEMA_TYPE_FIXED_ARRAY,
|
||||
SCHEMA_TYPE_ATOMIC,
|
||||
SCHEMA_TYPE_DECLARED_CLASS,
|
||||
SCHEMA_TYPE_DECLARED_ENUM,
|
||||
SCHEMA_TYPE_NONE,
|
||||
};
|
||||
|
||||
enum SchemaAtomicCategory_t : uint8
|
||||
{
|
||||
SCHEMA_ATOMIC_BASIC = 0,
|
||||
SCHEMA_ATOMIC_T,
|
||||
SCHEMA_ATOMIC_COLLECTION_OF_T,
|
||||
SCHEMA_ATOMIC_TF,
|
||||
SCHEMA_ATOMIC_TT,
|
||||
SCHEMA_ATOMIC_TTF,
|
||||
SCHEMA_ATOMIC_I,
|
||||
SCHEMA_ATOMIC_NONE,
|
||||
};
|
||||
|
||||
enum SchemaBuiltinType_t
|
||||
{
|
||||
SCHEMA_BUILTIN_INVALID = 0,
|
||||
SCHEMA_BUILTIN_VOID,
|
||||
SCHEMA_BUILTIN_CHAR,
|
||||
SCHEMA_BUILTIN_INT8,
|
||||
SCHEMA_BUILTIN_UINT8,
|
||||
SCHEMA_BUILTIN_INT16,
|
||||
SCHEMA_BUILTIN_UINT16,
|
||||
SCHEMA_BUILTIN_INT32,
|
||||
SCHEMA_BUILTIN_UINT32,
|
||||
SCHEMA_BUILTIN_INT64,
|
||||
SCHEMA_BUILTIN_UINT64,
|
||||
SCHEMA_BUILTIN_FLOAT32,
|
||||
SCHEMA_BUILTIN_FLOAT64,
|
||||
SCHEMA_BUILTIN_BOOL,
|
||||
SCHEMA_BUILTIN_COUNT,
|
||||
};
|
||||
|
||||
enum SchemaClassManipulatorAction_t
|
||||
{
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_REGISTER = 0,
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_REGISTER_PRE,
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_ALLOCATE,
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_DEALLOCATE,
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_CONSTRUCT_IN_PLACE,
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_DESCTRUCT_IN_PLACE,
|
||||
SCHEMA_CLASS_MANIPULATOR_ACTION_GET_SCHEMA_BINDING,
|
||||
};
|
||||
|
||||
enum SchemaAtomicManipulatorAction_t
|
||||
{
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_GET_COUNT = 0,
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_GET_ELEMENT_CONST,
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_GET_ELEMENT,
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_SWAP_ELEMENTS,
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_INSERT_BEFORE,
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_REMOVE_MULTIPLE,
|
||||
SCHEMA_ATOMIC_MANIPULATOR_ACTION_SET_COUNT,
|
||||
};
|
||||
|
||||
typedef void* (*SchemaClassManipulatorFn_t)(SchemaClassManipulatorAction_t, void*, void*);
|
||||
typedef void* (*SchemaAtomicManipulatorFn_t)(SchemaAtomicManipulatorAction_t, void*, void*, void*);
|
||||
|
||||
inline uint32 CSchemaType_Hash( const char *pString, int len )
|
||||
{
|
||||
return MurmurHash2( pString, len, 0xBAADFEED );
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct SchemaMetaInfoHandle_t
|
||||
{
|
||||
SchemaMetaInfoHandle_t() : m_pObj( NULL ) {}
|
||||
SchemaMetaInfoHandle_t( T *obj ) : m_pObj( obj ) {}
|
||||
T* Get() { return m_pObj; }
|
||||
|
||||
T* m_pObj;
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
class CSchemaPtrMap
|
||||
{
|
||||
public:
|
||||
CUtlMap<K, V> m_Map;
|
||||
CThreadFastMutex m_Mutex;
|
||||
};
|
||||
|
||||
class CSchemaType
|
||||
{
|
||||
public:
|
||||
virtual bool IsValid() { return false; }
|
||||
virtual const char* ToString( CBufferString& buff, bool bDontClearBuff ) { return ""; }
|
||||
virtual void SpewDescription( LoggingChannelID_t channelID, const char* pszName ) {}
|
||||
virtual bool GetSizeAndAlignment( int& nSize, uint8& nAlignment ) { return false; }
|
||||
virtual bool CanReinterpretAs( const CSchemaType* pType ) { return false; }
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType> GetInnerType() { return SchemaMetaInfoHandle_t<CSchemaType>(); }
|
||||
virtual SchemaMetaInfoHandle_t<CSchemaType> GetInnermostType() { return SchemaMetaInfoHandle_t<CSchemaType>(); }
|
||||
virtual bool IsA( const CSchemaType* pType ) { return false; }
|
||||
virtual bool InternalMatchInnerAs( SchemaTypeCategory_t eTypeCategory, SchemaAtomicCategory_t eAtomicCategory ) { return false; }
|
||||
|
||||
virtual void unk001() {}
|
||||
virtual void unk002() {}
|
||||
virtual void unk003() {}
|
||||
virtual void unk004() {}
|
||||
virtual void unk005() {}
|
||||
virtual void unk006() {}
|
||||
|
||||
virtual bool DependsOnlyOnUnresolvedOrGlobalTypes( ISchemaSystemTypeScope* pTypeScope ) { return false; }
|
||||
|
||||
virtual ~CSchemaType() = 0;
|
||||
|
||||
public:
|
||||
CUtlString m_sTypeName;
|
||||
CSchemaSystemTypeScope* m_pTypeScope;
|
||||
SchemaTypeCategory_t m_eTypeCategory;
|
||||
SchemaAtomicCategory_t m_eAtomicCategory;
|
||||
};
|
||||
|
||||
class CSchemaType_Builtin : public CSchemaType
|
||||
{
|
||||
public:
|
||||
SchemaBuiltinType_t m_eBuiltinType;
|
||||
uint8 m_nSize;
|
||||
};
|
||||
|
||||
class CSchemaType_Ptr : public CSchemaType
|
||||
{
|
||||
public:
|
||||
CSchemaType* m_pObjectType;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic : public CSchemaType
|
||||
{
|
||||
public:
|
||||
SchemaAtomicTypeInfo_t* m_pAtomicInfo;
|
||||
int m_nAtomicID;
|
||||
uint16 m_nSize;
|
||||
uint8 m_nAlignment;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic_T : public CSchemaType_Atomic
|
||||
{
|
||||
public:
|
||||
CSchemaType* m_pTemplateType;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic_CollectionOfT : public CSchemaType_Atomic_T
|
||||
{
|
||||
public:
|
||||
SchemaAtomicManipulatorFn_t m_pfnManipulator;
|
||||
uint16 m_nElementSize;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic_TF : public CSchemaType_Atomic_T
|
||||
{
|
||||
public:
|
||||
int m_nFuncPtrSize;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic_TT : public CSchemaType_Atomic_T
|
||||
{
|
||||
public:
|
||||
CSchemaType* m_pTemplateType2;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic_TTF : public CSchemaType_Atomic_TT
|
||||
{
|
||||
public:
|
||||
int m_nFuncPtrSize;
|
||||
};
|
||||
|
||||
class CSchemaType_Atomic_I : public CSchemaType_Atomic
|
||||
{
|
||||
public:
|
||||
int m_nInteger;
|
||||
};
|
||||
|
||||
class CSchemaType_DeclaredClass : public CSchemaType
|
||||
{
|
||||
public:
|
||||
CSchemaClassInfo* m_pClassInfo;
|
||||
bool m_bGlobalPromotionRequired;
|
||||
};
|
||||
|
||||
class CSchemaType_DeclaredEnum : public CSchemaType
|
||||
{
|
||||
public:
|
||||
CSchemaEnumInfo* m_pEnumInfo;
|
||||
bool m_bGlobalPromotionRequired;
|
||||
};
|
||||
|
||||
class CSchemaType_FixedArray : public CSchemaType
|
||||
{
|
||||
public:
|
||||
int m_nElementCount;
|
||||
uint16 m_nElementSize;
|
||||
uint8 m_nElementAlignment;
|
||||
CSchemaType* m_pElementType;
|
||||
};
|
||||
|
||||
class CSchemaType_Bitfield : public CSchemaType
|
||||
{
|
||||
public:
|
||||
int m_nSize;
|
||||
};
|
||||
|
||||
struct SchemaMetadataEntryData_t
|
||||
{
|
||||
const char* m_pszName;
|
||||
void* m_pData;
|
||||
};
|
||||
|
||||
struct SchemaClassFieldData_t
|
||||
{
|
||||
const char* m_pszName;
|
||||
|
||||
CSchemaType* m_pType;
|
||||
|
||||
int m_nSingleInheritanceOffset;
|
||||
|
||||
int m_nStaticMetadataCount;
|
||||
SchemaMetadataEntryData_t* m_pStaticMetadata;
|
||||
};
|
||||
|
||||
struct SchemaStaticFieldData_t
|
||||
{
|
||||
const char* m_pszName;
|
||||
|
||||
CSchemaType* m_pType;
|
||||
|
||||
void* m_pInstance;
|
||||
|
||||
int m_nStaticMetadataCount;
|
||||
SchemaMetadataEntryData_t* m_pStaticMetadata;
|
||||
};
|
||||
|
||||
struct SchemaBaseClassInfoData_t
|
||||
{
|
||||
uint m_nOffset;
|
||||
CSchemaClassInfo* m_pClass;
|
||||
};
|
||||
|
||||
struct SchemaClassInfoData_t
|
||||
{
|
||||
CSchemaClassInfo* m_pSchemaBinding;
|
||||
|
||||
const char* m_pszName;
|
||||
const char* m_pszProjectName;
|
||||
|
||||
int m_nSize;
|
||||
|
||||
uint16 m_nFieldCount;
|
||||
uint16 m_nStaticFieldCount;
|
||||
uint16 m_nStaticMetadataCount;
|
||||
|
||||
uint8 m_nAlignment;
|
||||
uint8 m_nBaseClassCount;
|
||||
|
||||
uint16 m_nMultipleInheritanceDepth;
|
||||
uint16 m_nSingleInheritanceDepth;
|
||||
|
||||
SchemaClassFieldData_t* m_pFields;
|
||||
SchemaStaticFieldData_t* m_pStaticFields;
|
||||
SchemaBaseClassInfoData_t* m_pBaseClasses;
|
||||
datamap_t* m_pDataDescMap;
|
||||
SchemaMetadataEntryData_t* m_pStaticMetadata;
|
||||
|
||||
CSchemaSystemTypeScope* m_pTypeScope;
|
||||
CSchemaType_DeclaredClass* m_pDeclaredClass;
|
||||
|
||||
uint m_nFlags1;
|
||||
uint m_nFlags2;
|
||||
|
||||
SchemaClassManipulatorFn_t m_pfnManipulator;
|
||||
};
|
||||
|
||||
class CSchemaClassInfo : public SchemaClassInfoData_t
|
||||
{
|
||||
};
|
||||
|
||||
struct SchemaEnumeratorInfoData_t
|
||||
{
|
||||
const char* m_pszName;
|
||||
|
||||
int64 m_nValue;
|
||||
|
||||
int m_nStaticMetadataCount;
|
||||
SchemaMetadataEntryData_t* m_pStaticMetadata;
|
||||
};
|
||||
|
||||
struct SchemaEnumInfoData_t
|
||||
{
|
||||
CSchemaEnumInfo* m_pSchemaBinding;
|
||||
|
||||
const char* m_pszName;
|
||||
const char* m_pszProjectName;
|
||||
|
||||
uint8 m_nSize;
|
||||
uint8 m_nAlignment;
|
||||
|
||||
uint16 m_nFlags;
|
||||
uint16 m_nEnumeratorCount;
|
||||
uint16 m_nStaticMetadataCount;
|
||||
|
||||
SchemaEnumeratorInfoData_t* m_pEnumerators;
|
||||
SchemaMetadataEntryData_t* m_pStaticMetadata;
|
||||
|
||||
CSchemaSystemTypeScope* m_pTypeScope;
|
||||
|
||||
int64 m_nMinEnumeratorValue;
|
||||
int64 m_nMaxEnumeratorValue;
|
||||
};
|
||||
|
||||
class CSchemaEnumInfo : public SchemaEnumInfoData_t
|
||||
{
|
||||
};
|
||||
|
||||
struct SchemaAtomicTypeInfo_t
|
||||
{
|
||||
const char* m_pszName1;
|
||||
const char* m_pszName2;
|
||||
|
||||
int m_nAtomicID;
|
||||
|
||||
int m_nStaticMetadataCount;
|
||||
SchemaMetadataEntryData_t* m_pStaticMetadata;
|
||||
};
|
||||
|
||||
struct AtomicTypeInfo_T_t
|
||||
{
|
||||
int m_nAtomicID;
|
||||
CSchemaType* m_pTemplateType;
|
||||
SchemaAtomicManipulatorFn_t m_pfnManipulator;
|
||||
};
|
||||
|
||||
struct AtomicTypeInfo_TF_t
|
||||
{
|
||||
int m_nAtomicID;
|
||||
CSchemaType* m_pTemplateType;
|
||||
int m_nFuncPtrSize;
|
||||
};
|
||||
|
||||
struct AtomicTypeInfo_TT_t
|
||||
{
|
||||
int m_nAtomicID;
|
||||
CSchemaType* m_pTemplateType;
|
||||
CSchemaType* m_pTemplateType2;
|
||||
};
|
||||
|
||||
struct AtomicTypeInfo_TTF_t
|
||||
{
|
||||
int m_nAtomicID;
|
||||
CSchemaType* m_pTemplateType;
|
||||
CSchemaType* m_pTemplateType2;
|
||||
int m_nFuncPtrSize;
|
||||
};
|
||||
|
||||
struct AtomicTypeInfo_I_t
|
||||
{
|
||||
int m_nAtomicID;
|
||||
int m_nInteger;
|
||||
};
|
||||
|
||||
struct TypeAndCountInfo_t
|
||||
{
|
||||
int m_nElementCount;
|
||||
CSchemaType* m_pElementType;
|
||||
};
|
||||
|
||||
#endif // SCHEMATYPES_H
|
@ -85,7 +85,7 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CLoggingSystem;
|
||||
class CThreadFastMutex;
|
||||
class CThreadSpinMutex;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Maximum length of a sprintf'ed logging message.
|
||||
@ -720,7 +720,7 @@ private:
|
||||
// Protects all data in this class except the registered channels
|
||||
// (which are supposed to be registered using the macros at static/global init time).
|
||||
// It is assumed that this mutex is reentrant safe on all platforms.
|
||||
CThreadFastMutex *m_pStateMutex;
|
||||
CThreadSpinMutex *m_pStateMutex;
|
||||
|
||||
// The index of the current "global" state of the logging system. By default, all threads use this state
|
||||
// for logging unless a given thread has pushed the logging state with bThreadLocal == true.
|
||||
|
@ -68,6 +68,13 @@
|
||||
#define MEMALLOC_REGION_FREE_5 '='
|
||||
#define MEMALLOC_REGION_FREE_6 '?'
|
||||
|
||||
enum MemAllocAttribute_t
|
||||
{
|
||||
MemAllocAttribute_Unk0 = 0,
|
||||
MemAllocAttribute_Unk1 = 1,
|
||||
MemAllocAttribute_Unk2 = 2
|
||||
};
|
||||
|
||||
enum MemoryState
|
||||
{
|
||||
MemoryState_UnexpectedlyAllocated = 0,
|
||||
@ -236,7 +243,7 @@ public:
|
||||
virtual int unk101() = 0;
|
||||
|
||||
// AMNOTE: Stub
|
||||
virtual void unk102() = 0;
|
||||
virtual void unk102( void *pMem, MemAllocAttribute_t alloc_attribute, int unk ) = 0;
|
||||
|
||||
// AMNOTE: Copies data to an unknown struct of byte size 56
|
||||
// Returns true if data was written, false otherwise
|
||||
|
@ -14,6 +14,10 @@
|
||||
#include "tier0/platform.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS_PC
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef POSIX
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
@ -38,10 +42,6 @@
|
||||
#pragma warning(disable:4251)
|
||||
#endif
|
||||
|
||||
#ifdef COMPILER_MSVC64
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
// #define THREAD_PROFILER 1
|
||||
|
||||
#define THREAD_MUTEX_TRACING_SUPPORTED
|
||||
@ -67,7 +67,11 @@ typedef void *HANDLE;
|
||||
|
||||
const unsigned TT_INFINITE = 0xffffffff;
|
||||
|
||||
typedef unsigned long ThreadId_t;
|
||||
#ifdef _WIN32
|
||||
typedef uint32 ThreadId_t;
|
||||
#else
|
||||
typedef uint64 ThreadId_t;
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
@ -98,24 +102,19 @@ typedef int (*ThreadedLoadLibraryFunc_t)();
|
||||
PLATFORM_INTERFACE void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func );
|
||||
PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc();
|
||||
|
||||
#if defined( _WIN32 )
|
||||
#if defined( PLATFORM_WINDOWS_PC )
|
||||
DLL_IMPORT unsigned long STDCALL GetCurrentThreadId();
|
||||
#define ThreadGetCurrentId GetCurrentThreadId
|
||||
#endif
|
||||
|
||||
inline void ThreadPause()
|
||||
{
|
||||
#if defined( COMPILER_GCC )
|
||||
__asm __volatile( "pause" );
|
||||
#elif defined ( COMPILER_MSVC64 )
|
||||
#if defined( PLATFORM_WINDOWS_PC )
|
||||
// Intrinsic for __asm pause; from <intrin.h>
|
||||
_mm_pause();
|
||||
#elif defined( COMPILER_MSVC32 )
|
||||
__asm pause;
|
||||
#elif defined( COMPILER_MSVCX360 )
|
||||
YieldProcessor();
|
||||
__asm { or r0,r0,r0 }
|
||||
YieldProcessor();
|
||||
__asm { or r1,r1,r1 }
|
||||
#elif defined( POSIX )
|
||||
__asm __volatile( "pause" );
|
||||
#elif defined( _X360 )
|
||||
#else
|
||||
#error "implement me"
|
||||
#endif
|
||||
@ -142,77 +141,59 @@ PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinity
|
||||
#define NOINLINE __attribute__ ((noinline))
|
||||
#endif
|
||||
|
||||
#ifndef _X360
|
||||
#define ThreadMemoryBarrier() ((void)0)
|
||||
// ThreadMemoryBarrier is a fence/barrier sufficient for most uses. It prevents reads
|
||||
// from moving past reads, and writes moving past writes. It is sufficient for
|
||||
// read-acquire and write-release barriers. It is not a full barrier and it does
|
||||
// not prevent reads from moving past writes -- that would require a full __sync()
|
||||
// on PPC and is significantly more expensive.
|
||||
#if defined( _X360 ) || defined( _PS3 )
|
||||
#define ThreadMemoryBarrier() __lwsync()
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
// Prevent compiler reordering across this barrier. This is
|
||||
// sufficient for most purposes on x86/x64.
|
||||
|
||||
#if _MSC_VER < 1500
|
||||
// !KLUDGE! For VC 2005
|
||||
// http://connect.microsoft.com/VisualStudio/feedback/details/100051
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
#endif
|
||||
#define ThreadMemoryBarrier() _ReadWriteBarrier()
|
||||
#elif defined(GNUC)
|
||||
// Prevent compiler reordering across this barrier. This is
|
||||
// sufficient for most purposes on x86/x64.
|
||||
// http://preshing.com/20120625/memory-ordering-at-compile-time
|
||||
#define ThreadMemoryBarrier() asm volatile("" ::: "memory")
|
||||
#else
|
||||
#define ThreadMemoryBarrier() __lwsync()
|
||||
#error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering
|
||||
#endif
|
||||
|
||||
#if defined( _LINUX ) || defined( _OSX )
|
||||
#define USE_INTRINSIC_INTERLOCKED
|
||||
#if defined( POSIX )
|
||||
// linux implementation
|
||||
inline int32 ThreadInterlockedIncrement( int32 volatile *p )
|
||||
{
|
||||
Assert( (size_t)p % 4 == 0 );
|
||||
return __sync_fetch_and_add( p, 1 ) + 1;
|
||||
}
|
||||
inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return __sync_add_and_fetch( p, 1 ); }
|
||||
inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return __sync_sub_and_fetch( p, 1 ); }
|
||||
inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return __sync_lock_test_and_set( p, value ); }
|
||||
inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return __sync_fetch_and_add( p, value ); }
|
||||
inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return __sync_val_compare_and_swap( p, comperand, value ); }
|
||||
inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return __sync_bool_compare_and_swap( p, comperand, value ); }
|
||||
|
||||
inline int32 ThreadInterlockedDecrement( int32 volatile *p )
|
||||
{
|
||||
Assert( (size_t)p % 4 == 0 );
|
||||
return __sync_fetch_and_add( p, -1 ) - 1;
|
||||
}
|
||||
inline int64 ThreadInterlockedIncrement64( int64 volatile *p ) { Assert( (size_t)p % 8 == 0 ); return __sync_add_and_fetch( p, 1 ); }
|
||||
inline int64 ThreadInterlockedDecrement64( int64 volatile *p ) { Assert( (size_t)p % 8 == 0 ); return __sync_sub_and_fetch( p, 1 ); }
|
||||
inline int64 ThreadInterlockedExchange64( int64 volatile *p, int64 value ) { Assert( (size_t)p % 8 == 0 ); return __sync_lock_test_and_set( p, value ); }
|
||||
inline int64 ThreadInterlockedExchangeAdd64( int64 volatile *p, int64 value ) { Assert( (size_t)p % 8 == 0 ); return __sync_fetch_and_add( p, value ); }
|
||||
inline int64 ThreadInterlockedCompareExchange64( int64 volatile *p, int64 value, int64 comperand ) { Assert( (size_t)p % 8 == 0 ); return __sync_val_compare_and_swap( p, comperand, value ); }
|
||||
inline bool ThreadInterlockedAssignIf64( int64 volatile *p, int64 value, int64 comperand ) { Assert( (size_t)p % 8 == 0 ); return __sync_bool_compare_and_swap( p, comperand, value ); }
|
||||
|
||||
inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value )
|
||||
{
|
||||
Assert( (size_t)p % 4 == 0 );
|
||||
int32 nRet;
|
||||
|
||||
// Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it.
|
||||
__asm __volatile(
|
||||
"xchgl %2,(%1)"
|
||||
: "=r" (nRet)
|
||||
: "r" (p), "0" (value)
|
||||
: "memory");
|
||||
return nRet;
|
||||
}
|
||||
|
||||
inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value )
|
||||
{
|
||||
Assert( (size_t)p % 4 == 0 );
|
||||
return __sync_fetch_and_add( p, value );
|
||||
}
|
||||
inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand )
|
||||
{
|
||||
Assert( (size_t)p % 4 == 0 );
|
||||
return __sync_val_compare_and_swap( p, comperand, value );
|
||||
}
|
||||
|
||||
|
||||
inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand )
|
||||
{
|
||||
Assert( (size_t)p % 4 == 0 );
|
||||
return __sync_bool_compare_and_swap( p, comperand, value );
|
||||
}
|
||||
|
||||
#elif ( defined( COMPILER_MSVC32 ) && ( _MSC_VER >= 1310 ) )
|
||||
// windows 32 implemnetation using compiler intrinsics
|
||||
#define USE_INTRINSIC_INTERLOCKED
|
||||
|
||||
extern "C"
|
||||
{
|
||||
long __cdecl _InterlockedIncrement(volatile long*);
|
||||
long __cdecl _InterlockedDecrement(volatile long*);
|
||||
long __cdecl _InterlockedExchange(volatile long*, long);
|
||||
long __cdecl _InterlockedExchangeAdd(volatile long*, long);
|
||||
long __cdecl _InterlockedCompareExchange(volatile long*, long, long);
|
||||
}
|
||||
|
||||
#pragma intrinsic( _InterlockedCompareExchange )
|
||||
inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { Assert( (size_t)p % sizeof(void*) == 0 ); return __sync_lock_test_and_set( p, value ); }
|
||||
inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { Assert( (size_t)p % sizeof(void*) == 0 ); return __sync_val_compare_and_swap( p, comperand, value ); }
|
||||
inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { Assert( (size_t)p % sizeof(void*) == 0 ); return __sync_bool_compare_and_swap( p, comperand, value ); }
|
||||
#elif ( defined( PLATFORM_WINDOWS_PC ) && ( _MSC_VER >= 1310 ) )
|
||||
// windows implemnetation using compiler intrinsics
|
||||
#pragma intrinsic( _InterlockedIncrement )
|
||||
#pragma intrinsic( _InterlockedDecrement )
|
||||
#pragma intrinsic( _InterlockedExchange )
|
||||
#pragma intrinsic( _InterlockedExchangeAdd )
|
||||
#pragma intrinsic( _InterlockedIncrement )
|
||||
#pragma intrinsic( _InterlockedCompareExchange )
|
||||
|
||||
inline int32 ThreadInterlockedIncrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedIncrement( (volatile long*)p ); }
|
||||
inline int32 ThreadInterlockedDecrement( int32 volatile *p ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedDecrement( (volatile long*)p ); }
|
||||
@ -220,44 +201,62 @@ inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) {
|
||||
inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedExchangeAdd( (volatile long*)p, value ); }
|
||||
inline int32 ThreadInterlockedCompareExchange( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return _InterlockedCompareExchange( (volatile long*)p, value, comperand ); }
|
||||
inline bool ThreadInterlockedAssignIf( int32 volatile *p, int32 value, int32 comperand ) { Assert( (size_t)p % 4 == 0 ); return ( _InterlockedCompareExchange( (volatile long*)p, value, comperand ) == comperand ); }
|
||||
|
||||
#if defined( PLATFORM_64BITS )
|
||||
#pragma intrinsic( _InterlockedIncrement64 )
|
||||
#pragma intrinsic( _InterlockedDecrement64 )
|
||||
#pragma intrinsic( _InterlockedExchange64 )
|
||||
#pragma intrinsic( _InterlockedExchangeAdd64 )
|
||||
#pragma intrinsic( _InterlockedCompareExchange64 )
|
||||
|
||||
inline int64 ThreadInterlockedIncrement64( int64 volatile *p ) { Assert( (size_t)p % 8 == 0 ); return _InterlockedIncrement64( (volatile __int64*)p ); }
|
||||
inline int64 ThreadInterlockedDecrement64( int64 volatile *p ) { Assert( (size_t)p % 8 == 0 ); return _InterlockedDecrement64( (volatile __int64*)p ); }
|
||||
inline int64 ThreadInterlockedExchange64( int64 volatile *p, int64 value ) { Assert( (size_t)p % 8 == 0 ); return _InterlockedExchange64( (volatile __int64*)p, value ); }
|
||||
inline int64 ThreadInterlockedExchangeAdd64( int64 volatile *p, int64 value ) { Assert( (size_t)p % 8 == 0 ); return _InterlockedExchangeAdd64( (volatile __int64*)p, value ); }
|
||||
inline int64 ThreadInterlockedCompareExchange64( int64 volatile *p, int64 value, int64 comperand ) { Assert( (size_t)p % 8 == 0 ); return _InterlockedCompareExchange64( (volatile __int64*)p, value, comperand ); }
|
||||
inline bool ThreadInterlockedAssignIf64( int64 volatile *p, int64 value, int64 comperand ) { Assert( (size_t)p % 8 == 0 ); return ( _InterlockedCompareExchange64( (volatile __int64*)p, value, comperand ) == comperand ); }
|
||||
#else
|
||||
// non 32-bit windows and 360 implementation
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE;
|
||||
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE;
|
||||
#endif
|
||||
|
||||
#pragma intrinsic( _InterlockedExchangePointer )
|
||||
#pragma intrinsic( _InterlockedCompareExchangePointer )
|
||||
|
||||
inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { Assert( (size_t)p % sizeof(void*) == 0 ); return _InterlockedExchangePointer( p, value ); }
|
||||
inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { Assert( (size_t)p % sizeof(void*) == 0 ); return _InterlockedCompareExchangePointer( p, value, comperand ); }
|
||||
inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { Assert( (size_t)p % sizeof(void*) == 0 ); return ( _InterlockedCompareExchangePointer( p, value, comperand ) == comperand ); }
|
||||
#else
|
||||
// 360 implementation
|
||||
PLATFORM_INTERFACE int32 ThreadInterlockedIncrement( int32 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( int32 volatile *, int32 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ) NOINLINE;
|
||||
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE;
|
||||
#endif
|
||||
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE;
|
||||
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE;
|
||||
|
||||
#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( PLATFORM_64BITS )
|
||||
#define TIPTR()
|
||||
inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)( ( intp )ThreadInterlockedExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value) ) ); }
|
||||
inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) ); }
|
||||
inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) == reinterpret_cast<intp>(comperand) ); }
|
||||
#else
|
||||
PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE;
|
||||
PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE;
|
||||
PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE;
|
||||
#endif
|
||||
|
||||
|
||||
inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); }
|
||||
|
||||
inline void const *ThreadInterlockedExchangePointerToConst( void const * volatile *p, void const *value ) { return ThreadInterlockedExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ) ); }
|
||||
inline void const *ThreadInterlockedCompareExchangePointerToConst( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedCompareExchangePointer( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); }
|
||||
inline bool ThreadInterlockedAssignPointerToConstIf( void const * volatile *p, void const *value, void const *comperand ) { return ThreadInterlockedAssignPointerIf( const_cast < void * volatile * > ( p ), const_cast < void * > ( value ), const_cast < void * > ( comperand ) ); }
|
||||
|
||||
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE;
|
||||
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64( volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE;
|
||||
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE;
|
||||
PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE;
|
||||
|
||||
inline unsigned ThreadInterlockedExchangeSubtract( uint32 volatile *p, uint32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, value ); }
|
||||
inline unsigned ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); }
|
||||
inline unsigned ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (int32 volatile *)p ); }
|
||||
@ -275,6 +274,35 @@ inline bool ThreadInterlockedAssignIf( uint32 volatile *p, uint32 value, uint32
|
||||
//inline bool ThreadInterlockedAssignIf( int volatile *p, int value, int comperand ) { return ThreadInterlockedAssignIf( (int32 volatile *)p, value, comperand ); }
|
||||
|
||||
|
||||
#if defined( PLATFORM_64BITS )
|
||||
#if defined (_WIN32)
|
||||
typedef __m128i int128;
|
||||
inline int128 int128_zero() { return _mm_setzero_si128(); }
|
||||
|
||||
#pragma intrinsic( _InterlockedCompareExchange128 )
|
||||
|
||||
inline bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand )
|
||||
{
|
||||
Assert( (size_t)pDest % 16 == 0 );
|
||||
|
||||
volatile int64 *pDest64 = ( volatile int64 * )pDest;
|
||||
int64 *pValue64 = ( int64 * )&value;
|
||||
int64 *pComperand64 = ( int64 * )&comperand;
|
||||
|
||||
return _InterlockedCompareExchange128( pDest64, pValue64[1], pValue64[0], pComperand64 ) == 1;
|
||||
}
|
||||
#else
|
||||
typedef __int128_t int128;
|
||||
#define int128_zero() 0
|
||||
|
||||
inline bool ThreadInterlockedAssignIf128( volatile int128 *pDest, const int128 &value, const int128 &comperand )
|
||||
{
|
||||
Assert( (size_t)pDest % 16 == 0 );
|
||||
return __sync_bool_compare_and_swap( pDest, comperand, value );
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Access to VTune thread profiling
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -544,7 +572,17 @@ template <typename T>
|
||||
class CInterlockedPtr
|
||||
{
|
||||
public:
|
||||
CInterlockedPtr() : m_value( 0 ) { COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int32) ); /* Will need to rework operator+= for 64 bit */ }
|
||||
CInterlockedPtr() : m_value( 0 )
|
||||
{
|
||||
#ifdef PLATFORM_64BITS
|
||||
COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int64) );
|
||||
#define THREADINTERLOCKEDEXCHANGEADD( _dest, _value ) ThreadInterlockedExchangeAdd64( (volatile int64 *)_dest, _value )
|
||||
#else // PLATFORM_64BITS
|
||||
COMPILE_TIME_ASSERT( sizeof(T *) == sizeof(int32) );
|
||||
#define THREADINTERLOCKEDEXCHANGEADD( _dest, _value ) ThreadInterlockedExchangeAdd( (volatile int32 *)_dest, _value )
|
||||
#endif // PLATFORM_64BITS
|
||||
}
|
||||
|
||||
CInterlockedPtr( T *value ) : m_value( value ) {}
|
||||
|
||||
operator T *() const { return m_value; }
|
||||
@ -553,21 +591,21 @@ public:
|
||||
bool operator==( T *rhs ) const { return ( m_value == rhs ); }
|
||||
bool operator!=( T *rhs ) const { return ( m_value != rhs ); }
|
||||
|
||||
T *operator++() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) )) + 1; }
|
||||
T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) ); }
|
||||
T *operator++() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, sizeof(T) )) + 1; }
|
||||
T *operator++(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, sizeof(T) ); }
|
||||
|
||||
T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) )) - 1; }
|
||||
T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) ); }
|
||||
T *operator--() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, -sizeof(T) )) - 1; }
|
||||
T *operator--(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, -sizeof(T) ); }
|
||||
|
||||
bool AssignIf( T *conditionValue, T *newValue ) { return ThreadInterlockedAssignPointerToConstIf( (void const **) &m_value, (void const *) newValue, (void const *) conditionValue ); }
|
||||
|
||||
T *operator=( T *newValue ) { ThreadInterlockedExchangePointerToConst( (void const **) &m_value, (void const *) newValue ); return newValue; }
|
||||
|
||||
void operator+=( int add ) { ThreadInterlockedExchangeAdd( (int32 *)&m_value, add * sizeof(T) ); }
|
||||
void operator+=( int add ) { THREADINTERLOCKEDEXCHANGEADD( &m_value, add * sizeof(T) ); }
|
||||
void operator-=( int subtract ) { operator+=( -subtract ); }
|
||||
|
||||
// Atomic add is like += except it returns the previous value as its return value
|
||||
T *AtomicAdd( int add ) { return ( T * ) ThreadInterlockedExchangeAdd( (int32 *)&m_value, add * sizeof(T) ); }
|
||||
T *AtomicAdd( int add ) { return ( T * ) THREADINTERLOCKEDEXCHANGEADD( &m_value, add * sizeof(T) ); }
|
||||
|
||||
T *operator+( int rhs ) const { return m_value + rhs; }
|
||||
T *operator-( int rhs ) const { return m_value - rhs; }
|
||||
@ -578,6 +616,8 @@ public:
|
||||
|
||||
private:
|
||||
T * volatile m_value;
|
||||
|
||||
#undef THREADINTERLOCKEDEXCHANGEADD
|
||||
};
|
||||
|
||||
|
||||
@ -591,22 +631,22 @@ private:
|
||||
class PLATFORM_CLASS CThreadMutex
|
||||
{
|
||||
public:
|
||||
CThreadMutex( const char* pDebugName );
|
||||
CThreadMutex( const char* pDebugName = NULL );
|
||||
~CThreadMutex();
|
||||
|
||||
//------------------------------------------------------
|
||||
// Mutex acquisition/release. Const intentionally defeated.
|
||||
//------------------------------------------------------
|
||||
void Lock( const char *pFileName, int nLine );
|
||||
void Lock( const char *pFileName, int nLine ) const { (const_cast<CThreadMutex *>(this))->Lock( pFileName, nLine ); }
|
||||
void Unlock( const char *pFileName, int nLine );
|
||||
void Unlock( const char *pFileName, int nLine ) const { (const_cast<CThreadMutex *>(this))->Unlock( pFileName, nLine ); }
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1 );
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1 ) const { (const_cast<CThreadMutex *>(this))->Lock( pFileName, nLine ); }
|
||||
void Unlock( const char *pFileName = NULL, int nLine = -1 );
|
||||
void Unlock( const char *pFileName = NULL, int nLine = -1 ) const { (const_cast<CThreadMutex *>(this))->Unlock( pFileName, nLine ); }
|
||||
|
||||
bool TryLock( const char *pFileName, int nLine );
|
||||
bool TryLock( const char *pFileName, int nLine ) const { return (const_cast<CThreadMutex *>(this))->TryLock( pFileName, nLine ); }
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 );
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const { return (const_cast<CThreadMutex *>(this))->TryLock( pFileName, nLine ); }
|
||||
|
||||
void LockSilent( const char *pFileName, int nLine ); // A Lock() operation which never spews. Required by the logging system to prevent badness.
|
||||
void UnlockSilent( const char *pFileName, int nLine ); // An Unlock() operation which never spews. Required by the logging system to prevent badness.
|
||||
void LockSilent( const char *pFileName = NULL, int nLine = -1 ); // A Lock() operation which never spews. Required by the logging system to prevent badness.
|
||||
void UnlockSilent( const char *pFileName = NULL, int nLine = -1 ); // An Unlock() operation which never spews. Required by the logging system to prevent badness.
|
||||
|
||||
//------------------------------------------------------
|
||||
// Use this to make deadlocks easier to track by asserting
|
||||
@ -642,14 +682,11 @@ private:
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
#ifdef THREAD_MUTEX_TRACING_SUPPORTED
|
||||
// Debugging (always herge to allow mixed debug/release builds w/o changing size)
|
||||
ThreadId_t m_currentOwnerID;
|
||||
uint16 m_lockCount;
|
||||
bool m_bTrace;
|
||||
const char* m_pDebugName;
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -664,19 +701,25 @@ private:
|
||||
|
||||
#if !defined(THREAD_PROFILER)
|
||||
|
||||
class CThreadFastMutex
|
||||
class CThreadSpinMutex
|
||||
{
|
||||
public:
|
||||
CThreadFastMutex()
|
||||
CThreadSpinMutex( const char* pDebugName = NULL )
|
||||
: m_ownerID( 0 ),
|
||||
m_depth( 0 )
|
||||
m_depth( 0 ),
|
||||
m_pDebugName( NULL/*pDebugName*/ )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
FORCEINLINE bool TryLockInline( const uint32 threadId ) volatile
|
||||
FORCEINLINE bool TryLockInline( const char *pFileName, int nLine, const ThreadId_t threadId ) volatile
|
||||
{
|
||||
if ( threadId != m_ownerID && !ThreadInterlockedAssignIf( (volatile int32 *)&m_ownerID, (int32)threadId, 0 ) )
|
||||
if ( threadId != m_ownerID && ( m_ownerID ||
|
||||
#ifdef _WIN32
|
||||
!ThreadInterlockedAssignIf( (volatile int32 *)&m_ownerID, (int32)threadId, 0 ) ) )
|
||||
#else
|
||||
!ThreadInterlockedAssignIf64( (volatile int64 *)&m_ownerID, (int64)threadId, 0 ) ) )
|
||||
#endif
|
||||
return false;
|
||||
|
||||
ThreadMemoryBarrier();
|
||||
@ -684,15 +727,15 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryLock( const uint32 threadId ) volatile
|
||||
bool TryLock( const char *pFileName, int nLine, const ThreadId_t threadId ) volatile
|
||||
{
|
||||
return TryLockInline( threadId );
|
||||
return TryLockInline( pFileName, nLine, threadId );
|
||||
}
|
||||
|
||||
PLATFORM_CLASS void Lock( const uint32 threadId, unsigned nSpinSleepTime ) volatile;
|
||||
PLATFORM_CLASS void Lock( const char *pFileName, int nLine, const ThreadId_t threadId, unsigned nSpinSleepTime ) volatile;
|
||||
|
||||
public:
|
||||
bool TryLock() volatile
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) volatile
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_depth == INT_MAX )
|
||||
@ -701,20 +744,20 @@ public:
|
||||
if ( m_depth < 0 )
|
||||
DebuggerBreak();
|
||||
#endif
|
||||
return TryLockInline( ThreadGetCurrentId() );
|
||||
return TryLockInline( pFileName, nLine, ThreadGetCurrentId() );
|
||||
}
|
||||
|
||||
#ifndef _DEBUG
|
||||
FORCEINLINE
|
||||
#endif
|
||||
void Lock( unsigned int nSpinSleepTime = 0 ) volatile
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1, unsigned int nSpinSleepTime = 0 ) volatile
|
||||
{
|
||||
const uint32 threadId = ThreadGetCurrentId();
|
||||
const ThreadId_t threadId = ThreadGetCurrentId();
|
||||
|
||||
if ( !TryLockInline( threadId ) )
|
||||
if ( !TryLockInline( pFileName, nLine, threadId ) )
|
||||
{
|
||||
ThreadPause();
|
||||
Lock( threadId, nSpinSleepTime );
|
||||
Lock( pFileName, nLine, threadId, nSpinSleepTime );
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
if ( m_ownerID != ThreadGetCurrentId() )
|
||||
@ -731,7 +774,7 @@ public:
|
||||
#ifndef _DEBUG
|
||||
FORCEINLINE
|
||||
#endif
|
||||
void Unlock() volatile
|
||||
void Unlock( const char *pFileName = NULL, int nLine = -1 ) volatile
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ownerID != ThreadGetCurrentId() )
|
||||
@ -745,41 +788,48 @@ public:
|
||||
if ( !m_depth )
|
||||
{
|
||||
ThreadMemoryBarrier();
|
||||
ThreadInterlockedExchange( &m_ownerID, 0 );
|
||||
#ifdef _WIN32
|
||||
ThreadInterlockedExchange( (volatile int32 *)&m_ownerID, 0 );
|
||||
#else
|
||||
ThreadInterlockedExchange64( (volatile int64 *)&m_ownerID, 0 );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool TryLock() const volatile { return (const_cast<CThreadFastMutex *>(this))->TryLock(); }
|
||||
void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadFastMutex *>(this))->Lock( nSpinSleepTime ); }
|
||||
void Unlock() const volatile { (const_cast<CThreadFastMutex *>(this))->Unlock(); }
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const volatile { return (const_cast<CThreadSpinMutex *>(this))->TryLock( pFileName, nLine ); }
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1, unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadSpinMutex *>(this))->Lock( pFileName, nLine, nSpinSleepTime ); }
|
||||
void Unlock( const char *pFileName = NULL, int nLine = -1 ) const volatile { (const_cast<CThreadSpinMutex *>(this))->Unlock( pFileName, nLine ); }
|
||||
|
||||
// To match regular CThreadMutex:
|
||||
bool AssertOwnedByCurrentThread() { return true; }
|
||||
void SetTrace( bool ) {}
|
||||
|
||||
uint32 GetOwnerId() const { return m_ownerID; }
|
||||
ThreadId_t GetOwnerId() const { return m_ownerID; }
|
||||
int GetDepth() const { return m_depth; }
|
||||
private:
|
||||
volatile uint32 m_ownerID;
|
||||
int m_depth;
|
||||
volatile ThreadId_t m_ownerID;
|
||||
int m_depth;
|
||||
const char* m_pDebugName;
|
||||
};
|
||||
|
||||
class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex
|
||||
class ALIGN128 CAlignedThreadFastMutex : public CThreadSpinMutex
|
||||
{
|
||||
public:
|
||||
CAlignedThreadFastMutex()
|
||||
CAlignedThreadFastMutex( const char* pDebugName = NULL ) : CThreadSpinMutex( pDebugName )
|
||||
{
|
||||
Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 );
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 pad[128-sizeof(CThreadFastMutex)];
|
||||
};
|
||||
uint8 pad[128-sizeof(CThreadSpinMutex)];
|
||||
} ALIGN128_POST;
|
||||
|
||||
#else
|
||||
typedef CThreadMutex CThreadFastMutex;
|
||||
typedef CThreadMutex CThreadSpinMutex;
|
||||
#endif
|
||||
|
||||
typedef CThreadSpinMutex CThreadFastMutex;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -787,17 +837,17 @@ typedef CThreadMutex CThreadFastMutex;
|
||||
class CThreadNullMutex
|
||||
{
|
||||
public:
|
||||
CThreadNullMutex( const char* pDebugName ) {}
|
||||
CThreadNullMutex( const char* pDebugName = NULL ) {}
|
||||
|
||||
static void Lock( const char *pFileName, int nLine ) {}
|
||||
static void Unlock( const char *pFileName, int nLine ) {}
|
||||
static void Lock( const char *pFileName = NULL, int nLine = -1 ) {}
|
||||
static void Unlock( const char *pFileName = NULL, int nLine = -1 ) {}
|
||||
|
||||
static bool TryLock( const char *pFileName, int nLine ) { return true; }
|
||||
static bool AssertOwnedByCurrentThread() { return true; }
|
||||
static bool TryLock( const char *pFileName = NULL, int nLine = -1 ) { return true; }
|
||||
static bool AssertOwnedByCurrentThread() { return true; }
|
||||
static void SetTrace( bool b ) {}
|
||||
|
||||
static uint32 GetOwnerId() { return 0; }
|
||||
static int GetDepth() { return 0; }
|
||||
static ThreadId_t GetOwnerId() { return 0; }
|
||||
static int GetDepth() { return 0; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -811,15 +861,17 @@ template <class BaseClass, bool *pCondition>
|
||||
class CThreadConditionalMutex : public BaseClass
|
||||
{
|
||||
public:
|
||||
void Lock() { if ( *pCondition ) BaseClass::Lock(); }
|
||||
void Lock() const { if ( *pCondition ) BaseClass::Lock(); }
|
||||
void Unlock() { if ( *pCondition ) BaseClass::Unlock(); }
|
||||
void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); }
|
||||
CThreadConditionalMutex( const char* pDebugName = NULL ) : BaseClass( pDebugName ) {}
|
||||
|
||||
bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; }
|
||||
bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; }
|
||||
bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; }
|
||||
void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); }
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1 ) { if ( *pCondition ) BaseClass::Lock( pFileName, nLine ); }
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1 ) const { if ( *pCondition ) BaseClass::Lock( pFileName, nLine ); }
|
||||
void Unlock( const char *pFileName = NULL, int nLine = -1 ) { if ( *pCondition ) BaseClass::Unlock( pFileName, nLine ); }
|
||||
void Unlock( const char *pFileName = NULL, int nLine = -1 ) const { if ( *pCondition ) BaseClass::Unlock( pFileName, nLine ); }
|
||||
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) { if ( *pCondition ) return BaseClass::TryLock( pFileName, nLine ); else return true; }
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const { if ( *pCondition ) return BaseClass::TryLock( pFileName, nLine ); else return true; }
|
||||
bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; }
|
||||
void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -830,10 +882,12 @@ template <class BaseClass>
|
||||
class CThreadTerminalMutex : public BaseClass
|
||||
{
|
||||
public:
|
||||
bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
|
||||
bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
|
||||
void Lock() { if ( !TryLock() ) BaseClass::Lock(); }
|
||||
void Lock() const { if ( !TryLock() ) BaseClass::Lock(); }
|
||||
CThreadTerminalMutex( const char* pDebugName = NULL ) : BaseClass( pDebugName ) {}
|
||||
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) { if ( !BaseClass::TryLock( pFileName, nLine ) ) { DebuggerBreak(); return false; } return true; }
|
||||
bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const { if ( !BaseClass::TryLock( pFileName, nLine ) ) { DebuggerBreak(); return false; } return true; }
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1 ) { if ( !TryLock( pFileName, nLine ) ) BaseClass::Lock( pFileName, nLine ); }
|
||||
void Lock( const char *pFileName = NULL, int nLine = -1 ) const { if ( !TryLock( pFileName, nLine ) ) BaseClass::Lock( pFileName, nLine ); }
|
||||
|
||||
};
|
||||
|
||||
@ -848,16 +902,16 @@ template <class MUTEX_TYPE = CThreadMutex>
|
||||
class CAutoLockT
|
||||
{
|
||||
public:
|
||||
FORCEINLINE CAutoLockT( MUTEX_TYPE &lock)
|
||||
FORCEINLINE CAutoLockT( MUTEX_TYPE &lock, const char *pFileName, int nLine )
|
||||
: m_lock(lock)
|
||||
{
|
||||
m_lock.Lock();
|
||||
m_lock.Lock( pFileName, nLine );
|
||||
}
|
||||
|
||||
FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock)
|
||||
FORCEINLINE CAutoLockT( const MUTEX_TYPE &lock, const char *pFileName, int nLine )
|
||||
: m_lock(const_cast<MUTEX_TYPE &>(lock))
|
||||
{
|
||||
m_lock.Lock();
|
||||
m_lock.Lock( pFileName, nLine );
|
||||
}
|
||||
|
||||
FORCEINLINE ~CAutoLockT()
|
||||
@ -870,33 +924,24 @@ private:
|
||||
MUTEX_TYPE &m_lock;
|
||||
|
||||
// Disallow copying
|
||||
CAutoLockT( const CAutoLockT<MUTEX_TYPE> & );
|
||||
CAutoLockT &operator=( const CAutoLockT<MUTEX_TYPE> & );
|
||||
CAutoLockT<MUTEX_TYPE>( const CAutoLockT<MUTEX_TYPE> & );
|
||||
CAutoLockT<MUTEX_TYPE> &operator=( const CAutoLockT<MUTEX_TYPE> & );
|
||||
};
|
||||
|
||||
typedef CAutoLockT<CThreadMutex> CAutoLock;
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
||||
template <int size> struct CAutoLockTypeDeducer {};
|
||||
template <> struct CAutoLockTypeDeducer<sizeof(CThreadMutex)> { typedef CThreadMutex Type_t; };
|
||||
template <> struct CAutoLockTypeDeducer<sizeof(CThreadNullMutex)> { typedef CThreadNullMutex Type_t; };
|
||||
#if !defined(THREAD_PROFILER)
|
||||
template <> struct CAutoLockTypeDeducer<sizeof(CThreadFastMutex)> { typedef CThreadFastMutex Type_t; };
|
||||
template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; };
|
||||
#endif
|
||||
|
||||
#define AUTO_LOCK_( type, mutex ) \
|
||||
CAutoLockT< type > UNIQUE_ID( static_cast<const type &>( mutex ) )
|
||||
CAutoLockT< type > UNIQUE_ID( static_cast<const type &>( mutex ), __FILE__, __LINE__ )
|
||||
|
||||
#ifdef COMPILER_GCC
|
||||
#define AUTO_LOCK( mutex ) \
|
||||
AUTO_LOCK_( typename CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex )
|
||||
#else
|
||||
#define AUTO_LOCK( mutex ) \
|
||||
AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex )
|
||||
#endif
|
||||
template<typename T> T strip_cv_quals_for_mutex(T&);
|
||||
template<typename T> T strip_cv_quals_for_mutex(const T&);
|
||||
template<typename T> T strip_cv_quals_for_mutex(volatile T&);
|
||||
template<typename T> T strip_cv_quals_for_mutex(const volatile T&);
|
||||
|
||||
#define AUTO_LOCK( mutex ) \
|
||||
AUTO_LOCK_( decltype(::strip_cv_quals_for_mutex(mutex)), mutex )
|
||||
|
||||
#define AUTO_LOCK_FM( mutex ) \
|
||||
AUTO_LOCK_( CThreadFastMutex, mutex )
|
||||
@ -1131,47 +1176,64 @@ private:
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class ALIGN8 PLATFORM_CLASS CThreadSpinRWLock
|
||||
#ifdef _WIN32
|
||||
class ALIGN8 CThreadSpinRWLock
|
||||
#else
|
||||
class ALIGN16 CThreadSpinRWLock
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
CThreadSpinRWLock() { COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 ); memset( (void*)this, 0, sizeof( *this ) ); }
|
||||
CThreadSpinRWLock( const char* pDebugName = NULL )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int64 ) ); Assert( (intp)this % 8 == 0 );
|
||||
#else
|
||||
COMPILE_TIME_ASSERT( sizeof( LockInfo_t ) == sizeof( int128 ) ); Assert( (intp)this % 16 == 0 );
|
||||
#endif
|
||||
memset( (void*)this, 0, sizeof( *this ) );
|
||||
|
||||
bool TryLockForWrite();
|
||||
bool TryLockForRead();
|
||||
//m_pDebugName = pDebugName;
|
||||
}
|
||||
|
||||
void LockForRead();
|
||||
void UnlockRead();
|
||||
void LockForWrite();
|
||||
void UnlockWrite();
|
||||
bool TryLockForWrite( const char *pFileName = NULL, int nLine = -1 );
|
||||
bool TryLockForRead( const char *pFileName = NULL, int nLine = -1 );
|
||||
|
||||
bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); }
|
||||
bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); }
|
||||
void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); }
|
||||
void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); }
|
||||
void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); }
|
||||
void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); }
|
||||
PLATFORM_CLASS void LockForRead( const char *pFileName = NULL, int nLine = -1 );
|
||||
PLATFORM_CLASS void UnlockRead( const char *pFileName = NULL, int nLine = -1 );
|
||||
void LockForWrite( const char *pFileName = NULL, int nLine = -1 );
|
||||
PLATFORM_CLASS void UnlockWrite( const char *pFileName = NULL, int nLine = -1 );
|
||||
|
||||
bool TryLockForWrite( const char *pFileName = NULL, int nLine = -1 ) const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite( pFileName, nLine ); }
|
||||
bool TryLockForRead( const char *pFileName = NULL, int nLine = -1 ) const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead( pFileName, nLine ); }
|
||||
|
||||
void LockForRead( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->LockForRead( pFileName, nLine ); }
|
||||
void UnlockRead( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead( pFileName, nLine ); }
|
||||
void LockForWrite( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite( pFileName, nLine ); }
|
||||
void UnlockWrite( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite( pFileName, nLine ); }
|
||||
|
||||
private:
|
||||
// This structure is used as an atomic & exchangeable 64-bit value. It would probably be better to just have one 64-bit value
|
||||
// and accessor functions that make/break it, but at this late stage of development, I'm just wrapping it into union
|
||||
// Beware of endianness: on Xbox/PowerPC m_writerId is high-word of m_i64; on PC, it's low-dword of m_i64
|
||||
union LockInfo_t
|
||||
struct LockInfo_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 m_writerId;
|
||||
int m_nReaders;
|
||||
};
|
||||
int64 m_i64;
|
||||
ThreadId_t m_writerId;
|
||||
#ifdef _WIN32
|
||||
int32 m_nReaders;
|
||||
#else
|
||||
int64 m_nReaders;
|
||||
#endif
|
||||
};
|
||||
|
||||
bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand );
|
||||
bool TryLockForWrite( const uint32 threadId );
|
||||
void SpinLockForWrite( const uint32 threadId );
|
||||
bool TryLockForWrite( const char *pFileName, int nLine, const ThreadId_t threadId );
|
||||
PLATFORM_CLASS void SpinLockForWrite( const char *pFileName, int nLine, const ThreadId_t threadId );
|
||||
|
||||
volatile LockInfo_t m_lockInfo;
|
||||
CInterlockedInt m_nWriters;
|
||||
const char* m_pDebugName;
|
||||
#ifdef _WIN32
|
||||
} ALIGN8_POST;
|
||||
#else
|
||||
} ALIGN16_POST;
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
@ -1494,7 +1556,7 @@ inline void CThreadMutex::Lock( const char *pFileName, int nLine )
|
||||
ThreadId_t thisThreadID = ThreadGetCurrentId();
|
||||
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||||
if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) )
|
||||
Msg( _T( "Thread %u about to wait for lock %x owned by %u\n" ), ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
|
||||
Msg( _T( "Thread %u about to wait for lock %p owned by %u\n" ), ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
|
||||
#endif
|
||||
|
||||
LockSilent( pFileName, nLine );
|
||||
@ -1505,7 +1567,7 @@ inline void CThreadMutex::Lock( const char *pFileName, int nLine )
|
||||
m_currentOwnerID = thisThreadID;
|
||||
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||||
if ( m_bTrace )
|
||||
Msg( _T( "Thread %u now owns lock 0x%x\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
|
||||
Msg( _T( "Thread %u now owns lock 0x%p\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
|
||||
#endif
|
||||
}
|
||||
m_lockCount++;
|
||||
@ -1523,7 +1585,7 @@ inline void CThreadMutex::Unlock( const char *pFileName, int nLine )
|
||||
{
|
||||
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||||
if ( m_bTrace )
|
||||
Msg( _T( "Thread %u releasing lock 0x%x\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
|
||||
Msg( _T( "Thread %u releasing lock 0x%p\n" ), m_currentOwnerID, (CRITICAL_SECTION *)&m_CriticalSection );
|
||||
#endif
|
||||
m_currentOwnerID = 0;
|
||||
}
|
||||
@ -1551,7 +1613,7 @@ inline bool CThreadMutex::AssertOwnedByCurrentThread()
|
||||
if (ThreadGetCurrentId() == m_currentOwnerID)
|
||||
return true;
|
||||
#ifdef THREAD_MUTEX_TRACING_ENABLED
|
||||
AssertMsg3( 0, "Expected thread %u as owner of lock 0x%x, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
|
||||
AssertMsg3( 0, "Expected thread %u as owner of lock 0x%p, but %u owns", ThreadGetCurrentId(), (CRITICAL_SECTION *)&m_CriticalSection, m_currentOwnerID );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@ -1570,7 +1632,7 @@ inline void CThreadMutex::SetTrace( bool bTrace )
|
||||
#elif defined(POSIX)
|
||||
|
||||
inline CThreadMutex::CThreadMutex( const char* pDebugName ) :
|
||||
m_currentOwnerID(0), m_lockCount(0), m_pDebugName(0)
|
||||
m_currentOwnerID(0), m_lockCount(0), m_pDebugName(NULL/*pDebugName*/)
|
||||
{
|
||||
// enable recursive locks as we need them
|
||||
pthread_mutexattr_init( &m_Attr );
|
||||
@ -1652,24 +1714,24 @@ inline CThreadRWLock::CThreadRWLock()
|
||||
|
||||
inline void CThreadRWLock::LockForRead()
|
||||
{
|
||||
m_mutex.Lock();
|
||||
m_mutex.Lock( __FILE__, __LINE__ );
|
||||
if ( m_nWriters)
|
||||
{
|
||||
WaitForRead();
|
||||
}
|
||||
m_nActiveReaders++;
|
||||
m_mutex.Unlock();
|
||||
m_mutex.Unlock( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
inline void CThreadRWLock::UnlockRead()
|
||||
{
|
||||
m_mutex.Lock();
|
||||
m_mutex.Lock( __FILE__, __LINE__ );
|
||||
m_nActiveReaders--;
|
||||
if ( m_nActiveReaders == 0 && m_nWriters != 0 )
|
||||
{
|
||||
m_CanWrite.Set();
|
||||
}
|
||||
m_mutex.Unlock();
|
||||
m_mutex.Unlock( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
|
||||
@ -1681,13 +1743,14 @@ inline void CThreadRWLock::UnlockRead()
|
||||
|
||||
inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand )
|
||||
{
|
||||
// Note: using unions guarantees no aliasing bugs. Casting structures through *(int64*)&
|
||||
// may create hard-to-catch bugs because when you do that, compiler doesn't know that the newly computed pointer
|
||||
// is actually aliased with LockInfo_t structure. It's rarely a problem in practice, but when it is, it's a royal pain to debug.
|
||||
return ThreadInterlockedAssignIf64( &m_lockInfo.m_i64, newValue.m_i64, comperand.m_i64 );
|
||||
#ifdef _WIN32
|
||||
return ThreadInterlockedAssignIf64( (volatile int64 *)&m_lockInfo, *((int64 *)&newValue), *((int64 *)&comperand) );
|
||||
#else
|
||||
return ThreadInterlockedAssignIf128( (volatile int128 *)&m_lockInfo, *((int128 *)&newValue), *((int128 *)&comperand) );
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId )
|
||||
FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const char *pFileName, int nLine, const ThreadId_t threadId )
|
||||
{
|
||||
// In order to grab a write lock, there can be no readers and no owners of the write lock
|
||||
if ( m_lockInfo.m_nReaders > 0 || ( m_lockInfo.m_writerId && m_lockInfo.m_writerId != threadId ) )
|
||||
@ -1695,8 +1758,8 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId )
|
||||
return false;
|
||||
}
|
||||
|
||||
static const LockInfo_t oldValue = {{ 0, 0 }};
|
||||
LockInfo_t newValue = {{ threadId, 0 }};
|
||||
static const LockInfo_t oldValue = { 0, 0 };
|
||||
LockInfo_t newValue = { threadId, 0 };
|
||||
if ( AssignIf( newValue, oldValue ) )
|
||||
{
|
||||
ThreadMemoryBarrier();
|
||||
@ -1705,10 +1768,10 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId )
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool CThreadSpinRWLock::TryLockForWrite()
|
||||
inline bool CThreadSpinRWLock::TryLockForWrite( const char *pFileName, int nLine )
|
||||
{
|
||||
m_nWriters++;
|
||||
if ( !TryLockForWrite( ThreadGetCurrentId() ) )
|
||||
if ( !TryLockForWrite( pFileName, nLine, ThreadGetCurrentId() ) )
|
||||
{
|
||||
m_nWriters--;
|
||||
return false;
|
||||
@ -1716,7 +1779,7 @@ inline bool CThreadSpinRWLock::TryLockForWrite()
|
||||
return true;
|
||||
}
|
||||
|
||||
FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
|
||||
FORCEINLINE bool CThreadSpinRWLock::TryLockForRead( const char *pFileName, int nLine )
|
||||
{
|
||||
if ( m_nWriters != 0 )
|
||||
{
|
||||
@ -1726,21 +1789,10 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
|
||||
LockInfo_t oldValue;
|
||||
LockInfo_t newValue;
|
||||
|
||||
if( IsX360() )
|
||||
{
|
||||
// this is the code equivalent to original code (see below) that doesn't cause LHS on Xbox360
|
||||
// WARNING: This code assumes BIG Endian CPU
|
||||
oldValue.m_i64 = uint32( m_lockInfo.m_nReaders );
|
||||
newValue.m_i64 = oldValue.m_i64 + 1; // NOTE: when we have -1 (or 0xFFFFFFFF) readers, this will result in non-equivalent code
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is the original code that worked here for a while
|
||||
oldValue.m_nReaders = m_lockInfo.m_nReaders;
|
||||
oldValue.m_writerId = 0;
|
||||
newValue.m_nReaders = oldValue.m_nReaders + 1;
|
||||
newValue.m_writerId = 0;
|
||||
}
|
||||
oldValue.m_nReaders = m_lockInfo.m_nReaders;
|
||||
oldValue.m_writerId = 0;
|
||||
newValue.m_nReaders = oldValue.m_nReaders + 1;
|
||||
newValue.m_writerId = 0;
|
||||
|
||||
if ( AssignIf( newValue, oldValue ) )
|
||||
{
|
||||
@ -1750,16 +1802,16 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void CThreadSpinRWLock::LockForWrite()
|
||||
inline void CThreadSpinRWLock::LockForWrite( const char *pFileName, int nLine )
|
||||
{
|
||||
const uint32 threadId = ThreadGetCurrentId();
|
||||
const ThreadId_t threadId = ThreadGetCurrentId();
|
||||
|
||||
m_nWriters++;
|
||||
|
||||
if ( !TryLockForWrite( threadId ) )
|
||||
if ( !TryLockForWrite( pFileName, nLine, threadId ) )
|
||||
{
|
||||
ThreadPause();
|
||||
SpinLockForWrite( threadId );
|
||||
SpinLockForWrite( pFileName, nLine, threadId );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,9 @@ template <class T>
|
||||
class CUtlStringMap
|
||||
{
|
||||
public:
|
||||
CUtlStringMap( bool caseInsensitive = true ) : m_SymbolTable( 0, 32, caseInsensitive )
|
||||
CUtlStringMap( bool caseInsensitive = true, int initsize = 32 ) :
|
||||
m_SymbolTable( 0, 32, caseInsensitive ),
|
||||
m_Vector( initsize )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,13 +34,13 @@ public:
|
||||
DLL_CLASS_IMPORT void Purge( void );
|
||||
DLL_CLASS_IMPORT MemBlockHandle_t Alloc( unsigned int nSize );
|
||||
DLL_CLASS_IMPORT MemBlockHandle_t AllocAndCopy( const char* pBuf, unsigned int nSize );
|
||||
DLL_CLASS_IMPORT uint64 MemUsage( void );
|
||||
DLL_CLASS_IMPORT size_t MemUsage( void ) const;
|
||||
DLL_CLASS_IMPORT void SetPageSize( unsigned int nPageSize );
|
||||
DLL_CLASS_IMPORT MemBlockHandle_t FindPageWithSpace( unsigned int nSpace );
|
||||
|
||||
void* GetBlock( MemBlockHandle_t handle ) const;
|
||||
|
||||
private:
|
||||
DLL_CLASS_IMPORT int FindPageWithSpace( unsigned int nSpace ) const;
|
||||
|
||||
struct MemPage_t
|
||||
{
|
||||
|
@ -28,34 +28,30 @@
|
||||
// Purpose: Optimized pool memory allocator
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef void (*MemoryPoolReportFunc_t)( char const* pMsg, ... );
|
||||
// Ways the memory pool can grow when it needs to make a new blob.
|
||||
enum MemoryPoolGrowType_t
|
||||
{
|
||||
UTLMEMORYPOOL_GROW_NONE=0, // Don't allow new blobs.
|
||||
UTLMEMORYPOOL_GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates get larger and larger each time it allocates one).
|
||||
UTLMEMORYPOOL_GROW_SLOW=2, // New blob size is numElements.
|
||||
UTLMEMORYPOOL_GROW_RBTREE=3 // No blobs. All blocks are stored in RBTree.
|
||||
};
|
||||
|
||||
class CUtlMemoryPool
|
||||
class CUtlMemoryPoolBase
|
||||
{
|
||||
public:
|
||||
// Ways the memory pool can grow when it needs to make a new blob.
|
||||
enum MemoryPoolGrowType_t
|
||||
{
|
||||
GROW_NONE=0, // Don't allow new blobs.
|
||||
GROW_FAST=1, // New blob size is numElements * (i+1) (ie: the blocks it allocates
|
||||
// get larger and larger each time it allocates one).
|
||||
GROW_SLOW=2 // New blob size is numElements.
|
||||
};
|
||||
DLL_CLASS_IMPORT CUtlMemoryPoolBase( int blockSize, int numElements, int nAlignment = 0, MemoryPoolGrowType_t growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, MemAllocAttribute_t allocAttribute = MemAllocAttribute_Unk0 );
|
||||
DLL_CLASS_IMPORT ~CUtlMemoryPoolBase();
|
||||
|
||||
CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 );
|
||||
~CUtlMemoryPool();
|
||||
// Resets the pool
|
||||
DLL_CLASS_IMPORT void Init( int blockSize, int numElements, int nAlignment, MemoryPoolGrowType_t growMode, const char *pszAllocOwner, MemAllocAttribute_t allocAttribute );
|
||||
|
||||
void* Alloc(); // Allocate the element size you specified in the constructor.
|
||||
void* Alloc( size_t amount );
|
||||
void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction
|
||||
void* AllocZero( size_t amount );
|
||||
void Free(void *pMem);
|
||||
DLL_CLASS_IMPORT void* Alloc(); // Allocate the element size you specified in the constructor.
|
||||
DLL_CLASS_IMPORT void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction
|
||||
DLL_CLASS_IMPORT void Free( void *pMem );
|
||||
|
||||
// Frees everything
|
||||
void Clear();
|
||||
|
||||
// Error reporting...
|
||||
static void SetErrorReportFunc( MemoryPoolReportFunc_t func );
|
||||
DLL_CLASS_IMPORT void Clear();
|
||||
|
||||
// returns number of allocated blocks
|
||||
int Count() const { return m_BlocksAllocated; }
|
||||
@ -63,62 +59,47 @@ public:
|
||||
int BlockSize() const { return m_BlockSize; }
|
||||
int Size() const { return m_NumBlobs * m_BlocksPerBlob * m_BlockSize; }
|
||||
|
||||
bool IsAllocationWithinPool( void *pMem ) const;
|
||||
DLL_CLASS_IMPORT bool IsAllocationWithinPool( void *pMem ) const;
|
||||
|
||||
protected:
|
||||
struct FreeList_t
|
||||
{
|
||||
FreeList_t *m_pNext;
|
||||
};
|
||||
|
||||
class CBlob
|
||||
{
|
||||
public:
|
||||
CBlob *m_pPrev, *m_pNext;
|
||||
int m_NumBytes; // Number of bytes in this blob.
|
||||
CBlob *m_pNext;
|
||||
int m_NumBytes; // Number of bytes in this blob.
|
||||
char m_Data[1];
|
||||
char m_Padding[3]; // to int align the struct
|
||||
};
|
||||
|
||||
// Resets the pool
|
||||
void Init();
|
||||
void AddNewBlob();
|
||||
void ReportLeaks();
|
||||
DLL_CLASS_IMPORT FreeList_t* AddNewBlob();
|
||||
DLL_CLASS_IMPORT void ResetAllocationCounts();
|
||||
DLL_CLASS_IMPORT void InternalClear( CBlob *blob, FreeList_t *free_list );
|
||||
DLL_CLASS_IMPORT void ClearDestruct( void (*)( void* ) );
|
||||
|
||||
int m_BlockSize;
|
||||
int m_BlocksPerBlob;
|
||||
|
||||
int m_GrowMode; // GROW_ enum.
|
||||
MemoryPoolGrowType_t m_GrowMode;
|
||||
|
||||
int m_BlocksAllocated;
|
||||
int m_PeakAlloc;
|
||||
CInterlockedInt m_BlocksAllocated;
|
||||
CInterlockedInt m_PeakAlloc;
|
||||
unsigned short m_nAlignment;
|
||||
unsigned short m_NumBlobs;
|
||||
|
||||
// FIXME: Change m_ppMemBlob into a growable array?
|
||||
void *m_pHeadOfFreeList;
|
||||
const char * m_pszAllocOwner;
|
||||
// CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned
|
||||
CBlob m_BlobHead;
|
||||
FreeList_t** m_ppTailOfFreeList;
|
||||
FreeList_t* m_pHeadOfFreeList;
|
||||
|
||||
static MemoryPoolReportFunc_t g_ReportFunc;
|
||||
};
|
||||
CBlob** m_ppBlobTail;
|
||||
CBlob* m_pBlobHead;
|
||||
|
||||
MemAllocAttribute_t m_AllocAttribute;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Multi-thread/Thread Safe Memory Class
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMemoryPoolMT : public CUtlMemoryPool
|
||||
{
|
||||
public:
|
||||
CMemoryPoolMT( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment ) {}
|
||||
|
||||
|
||||
void* Alloc() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc(); }
|
||||
void* Alloc( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Alloc( amount ); }
|
||||
void* AllocZero() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero(); }
|
||||
void* AllocZero( size_t amount ) { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::AllocZero( amount ); }
|
||||
void Free(void *pMem) { AUTO_LOCK( m_mutex ); CUtlMemoryPool::Free( pMem ); }
|
||||
|
||||
// Frees everything
|
||||
void Clear() { AUTO_LOCK( m_mutex ); return CUtlMemoryPool::Clear(); }
|
||||
private:
|
||||
CThreadFastMutex m_mutex; // @TODO: Rework to use tslist (toml 7/6/2007)
|
||||
bool m_Unk1;
|
||||
};
|
||||
|
||||
|
||||
@ -127,19 +108,26 @@ private:
|
||||
// and construction and destruction of objects.
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
class CClassMemoryPool : public CUtlMemoryPool
|
||||
class CUtlMemoryPool : public CUtlMemoryPoolBase
|
||||
{
|
||||
public:
|
||||
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) :
|
||||
CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {}
|
||||
CUtlMemoryPool( int numElements, MemoryPoolGrowType_t growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = MEM_ALLOC_CLASSNAME(T), MemAllocAttribute_t allocAttribute = MemAllocAttribute_Unk0 )
|
||||
: CUtlMemoryPoolBase( sizeof(T), numElements, alignof(T), growMode, pszAllocOwner, allocAttribute ) {}
|
||||
|
||||
T* Alloc();
|
||||
T* AllocZero();
|
||||
void Free( T *pMem );
|
||||
|
||||
void Clear();
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Multi-thread/Thread Safe Memory Class
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
using CUtlMemoryPoolMT = CUtlMemoryPool<T>;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specialized pool for aligned data management (e.g., Xbox textures)
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -317,13 +305,13 @@ public:
|
||||
|
||||
|
||||
template< class T >
|
||||
inline T* CClassMemoryPool<T>::Alloc()
|
||||
inline T* CUtlMemoryPool<T>::Alloc()
|
||||
{
|
||||
T *pRet;
|
||||
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
pRet = (T*)CUtlMemoryPool::Alloc();
|
||||
pRet = (T*)CUtlMemoryPoolBase::Alloc();
|
||||
}
|
||||
|
||||
if ( pRet )
|
||||
@ -334,13 +322,13 @@ inline T* CClassMemoryPool<T>::Alloc()
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline T* CClassMemoryPool<T>::AllocZero()
|
||||
inline T* CUtlMemoryPool<T>::AllocZero()
|
||||
{
|
||||
T *pRet;
|
||||
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
pRet = (T*)CUtlMemoryPool::AllocZero();
|
||||
pRet = (T*)CUtlMemoryPoolBase::AllocZero();
|
||||
}
|
||||
|
||||
if ( pRet )
|
||||
@ -351,44 +339,20 @@ inline T* CClassMemoryPool<T>::AllocZero()
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline void CClassMemoryPool<T>::Free(T *pMem)
|
||||
inline void CUtlMemoryPool<T>::Free(T *pMem)
|
||||
{
|
||||
if ( pMem )
|
||||
{
|
||||
Destruct( pMem );
|
||||
}
|
||||
|
||||
CUtlMemoryPool::Free( pMem );
|
||||
CUtlMemoryPoolBase::Free( pMem );
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline void CClassMemoryPool<T>::Clear()
|
||||
inline void CUtlMemoryPool<T>::Clear()
|
||||
{
|
||||
CUtlRBTree<void *> freeBlocks;
|
||||
SetDefLessFunc( freeBlocks );
|
||||
|
||||
void *pCurFree = m_pHeadOfFreeList;
|
||||
while ( pCurFree != NULL )
|
||||
{
|
||||
freeBlocks.Insert( pCurFree );
|
||||
pCurFree = *((void**)pCurFree);
|
||||
}
|
||||
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
T *p = (T *)pCur->m_Data;
|
||||
T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes);
|
||||
while ( p < pLimit )
|
||||
{
|
||||
if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() )
|
||||
{
|
||||
Destruct( p );
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
CUtlMemoryPool::Clear();
|
||||
CUtlMemoryPoolBase::ClearDestruct( (void (*)( void* ))&Destruct<T> );
|
||||
}
|
||||
|
||||
|
||||
@ -399,30 +363,27 @@ inline void CClassMemoryPool<T>::Clear()
|
||||
//-----------------------------------------------------------------------------
|
||||
#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \
|
||||
public: \
|
||||
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
|
||||
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
|
||||
inline void operator delete( void* p ) { s_Allocator.Free(p); } \
|
||||
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
|
||||
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " CUtlMemoryPool"); return s_Allocator.Alloc(); } \
|
||||
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " CUtlMemoryPool"); return s_Allocator.Alloc(); } \
|
||||
inline void operator delete( void* p ) { s_Allocator.Free((_class*)p); } \
|
||||
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free((_class*)p); } \
|
||||
private: \
|
||||
static CUtlMemoryPool s_Allocator
|
||||
static CUtlMemoryPool<_class> s_Allocator
|
||||
|
||||
#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \
|
||||
CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
|
||||
|
||||
#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \
|
||||
CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment )
|
||||
CUtlMemoryPool<_class> _class::s_Allocator(_initsize, _grow, #_class " CUtlMemoryPool", MemAllocAttribute_Unk2)
|
||||
|
||||
#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \
|
||||
public: \
|
||||
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
|
||||
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_Allocator.Alloc(size); } \
|
||||
inline void operator delete( void* p ) { s_Allocator.Free(p); } \
|
||||
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free(p); } \
|
||||
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " CUtlMemoryPoolMT"); return s_Allocator.Alloc(); } \
|
||||
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " CUtlMemoryPoolMT"); return s_Allocator.Alloc(); } \
|
||||
inline void operator delete( void* p ) { s_Allocator.Free((_class*)p); } \
|
||||
inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free((_class*)p); } \
|
||||
private: \
|
||||
static CMemoryPoolMT s_Allocator
|
||||
static CUtlMemoryPoolMT<_class> s_Allocator
|
||||
|
||||
#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \
|
||||
CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool")
|
||||
CUtlMemoryPoolMT<_class> _class::s_Allocator(_initsize, _grow, #_class " CUtlMemoryPoolMT", MemAllocAttribute_Unk2)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Macros that make it simple to make a class use a fixed-size allocator
|
||||
@ -433,14 +394,14 @@ inline void CClassMemoryPool<T>::Clear()
|
||||
|
||||
#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \
|
||||
public: \
|
||||
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
|
||||
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " pool"); return s_pAllocator->Alloc(size); } \
|
||||
inline void operator delete( void* p ) { s_pAllocator->Free(p); } \
|
||||
inline void* operator new( size_t size ) { MEM_ALLOC_CREDIT_(#_class " CUtlMemoryPool"); return s_pAllocator->Alloc(); } \
|
||||
inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { MEM_ALLOC_CREDIT_(#_class " CUtlMemoryPool"); return s_pAllocator->Alloc(); } \
|
||||
inline void operator delete( void* p ) { s_pAllocator->Free((_class*)p); } \
|
||||
private: \
|
||||
static CUtlMemoryPool* s_pAllocator
|
||||
static CUtlMemoryPool<_class>* s_pAllocator
|
||||
|
||||
#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \
|
||||
CUtlMemoryPool* _class::s_pAllocator = _allocator
|
||||
CUtlMemoryPool<_class>* _class::s_pAllocator = _allocator
|
||||
|
||||
|
||||
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >
|
||||
|
@ -14,11 +14,12 @@
|
||||
#endif
|
||||
|
||||
#include "tier0/threadtools.h"
|
||||
#include "tier1/utlrbtree.h"
|
||||
#include "tier1/utlvector.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include "tier1/utllinkedlist.h"
|
||||
#include "tier1/stringpool.h"
|
||||
#include "tier1/utlhashtable.h"
|
||||
#include "tier1/memblockallocator.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -41,7 +42,6 @@ public:
|
||||
// constructor, destructor
|
||||
CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {}
|
||||
CUtlSymbol( UtlSymId_t id ) : m_Id(id) {}
|
||||
CUtlSymbol( const char* pStr );
|
||||
CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {}
|
||||
|
||||
// operator=
|
||||
@ -49,35 +49,19 @@ public:
|
||||
|
||||
// operator==
|
||||
bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; }
|
||||
bool operator==( const char* pStr ) const;
|
||||
|
||||
|
||||
// Is valid?
|
||||
bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
|
||||
|
||||
// Gets at the symbol
|
||||
operator UtlSymId_t const() const { return m_Id; }
|
||||
|
||||
// Gets the string associated with the symbol
|
||||
operator UtlSymId_t () const { return m_Id; }
|
||||
|
||||
protected:
|
||||
CUtlSymbol( const char* pStr );
|
||||
bool operator==( const char* pStr ) const;
|
||||
const char* String( ) const;
|
||||
|
||||
// Modules can choose to disable the static symbol table so to prevent accidental use of them.
|
||||
static void DisableStaticSymbolTable();
|
||||
|
||||
protected:
|
||||
UtlSymId_t m_Id;
|
||||
|
||||
// Initializes the symbol table
|
||||
static void Initialize();
|
||||
|
||||
// returns the current symbol table
|
||||
static CUtlSymbolTableMT* CurrTable();
|
||||
|
||||
// The standard global symbol table
|
||||
static CUtlSymbolTableMT* s_pSymbolTable;
|
||||
|
||||
static bool s_bAllowStaticSymbolTable;
|
||||
|
||||
friend class CCleanupUtlSymbolTable;
|
||||
};
|
||||
|
||||
|
||||
@ -98,91 +82,74 @@ class CUtlSymbolTable
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
|
||||
~CUtlSymbolTable();
|
||||
DLL_CLASS_IMPORT CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
|
||||
DLL_CLASS_IMPORT ~CUtlSymbolTable();
|
||||
|
||||
// Finds and/or creates a symbol based on the string
|
||||
CUtlSymbol AddString( const char* pString, bool* created = NULL );
|
||||
DLL_CLASS_IMPORT CUtlSymbol AddString( const char* pString, bool* created = NULL );
|
||||
DLL_CLASS_IMPORT CUtlSymbol AddString( const char* pString, int nLength, bool* created = NULL );
|
||||
|
||||
// Finds the symbol for pString
|
||||
CUtlSymbol Find( const char* pString ) const;
|
||||
DLL_CLASS_IMPORT CUtlSymbol Find( const char* pString ) const;
|
||||
DLL_CLASS_IMPORT CUtlSymbol Find( const char* pString, int nLength ) const;
|
||||
|
||||
// Look up the string associated with a particular symbol
|
||||
const char* String( CUtlSymbol id ) const;
|
||||
DLL_CLASS_IMPORT const char* String( CUtlSymbol id ) const;
|
||||
|
||||
// Remove all symbols in the table.
|
||||
void RemoveAll();
|
||||
DLL_CLASS_IMPORT void RemoveAll();
|
||||
DLL_CLASS_IMPORT void Purge();
|
||||
|
||||
// Returns elements in the table
|
||||
DLL_CLASS_IMPORT int GetElements( int nFirstElement, int nCount, CUtlSymbol *pElements ) const;
|
||||
|
||||
DLL_CLASS_IMPORT size_t GetMemoryUsage() const;
|
||||
|
||||
DLL_CLASS_IMPORT void SetPageSize( unsigned int nSize );
|
||||
|
||||
DLL_CLASS_IMPORT bool SaveToBuffer( CUtlBuffer& buff ) const;
|
||||
DLL_CLASS_IMPORT bool RestoreFromBuffer( CUtlBuffer& buff );
|
||||
|
||||
int GetNumStrings( void ) const
|
||||
{
|
||||
return m_Lookup.Count();
|
||||
return m_MemBlocks.Count();
|
||||
}
|
||||
|
||||
// We store one of these at the beginning of every string to speed
|
||||
// up comparisons.
|
||||
typedef unsigned short hashDecoration_t;
|
||||
|
||||
protected:
|
||||
class CStringPoolIndex
|
||||
struct UtlSymTableAltKey
|
||||
{
|
||||
const CUtlSymbolTable* m_pTable;
|
||||
const char* m_pString;
|
||||
int m_nLength;
|
||||
};
|
||||
|
||||
struct UtlSymTableHashFunctor
|
||||
{
|
||||
public:
|
||||
inline CStringPoolIndex()
|
||||
{
|
||||
}
|
||||
ptrdiff_t m_ownerOffset;
|
||||
|
||||
inline CStringPoolIndex( unsigned short iPool, unsigned short iOffset )
|
||||
: m_iPool(iPool), m_iOffset(iOffset)
|
||||
{}
|
||||
|
||||
inline bool operator==( const CStringPoolIndex &other ) const
|
||||
{
|
||||
return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset;
|
||||
}
|
||||
|
||||
unsigned short m_iPool; // Index into m_StringPools.
|
||||
unsigned short m_iOffset; // Index into the string pool.
|
||||
UtlSymTableHashFunctor();
|
||||
unsigned int operator()( UtlSymTableAltKey k ) const;
|
||||
unsigned int operator()( int k ) const;
|
||||
};
|
||||
|
||||
class CLess
|
||||
struct UtlSymTableEqualFunctor
|
||||
{
|
||||
public:
|
||||
CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
|
||||
bool operator!() const { return false; }
|
||||
bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const;
|
||||
ptrdiff_t m_ownerOffset;
|
||||
|
||||
UtlSymTableEqualFunctor();
|
||||
bool operator()( int a, int b ) const;
|
||||
bool operator()( UtlSymTableAltKey a, int b ) const;
|
||||
bool operator()( int a, UtlSymTableAltKey b ) const;
|
||||
};
|
||||
|
||||
// Stores the symbol lookup
|
||||
class CTree : public CUtlRBTree<CStringPoolIndex, unsigned short, CLess>
|
||||
{
|
||||
public:
|
||||
CTree( int growSize, int initSize ) : CUtlRBTree<CStringPoolIndex, unsigned short, CLess>( growSize, initSize ) {}
|
||||
friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table
|
||||
};
|
||||
typedef CUtlHashtable<int, empty_t, UtlSymTableHashFunctor, UtlSymTableEqualFunctor, UtlSymTableAltKey> Hashtable_t;
|
||||
typedef CUtlVector<MemBlockHandle_t> MemBlocksVec_t;
|
||||
|
||||
struct StringPool_t
|
||||
{
|
||||
int m_TotalLen; // How large is
|
||||
int m_SpaceUsed;
|
||||
char m_Data[1];
|
||||
};
|
||||
|
||||
CTree m_Lookup;
|
||||
Hashtable_t m_HashTable;
|
||||
MemBlocksVec_t m_MemBlocks;
|
||||
CUtlMemoryBlockAllocator m_MemBlockAllocator;
|
||||
|
||||
bool m_bInsensitive;
|
||||
mutable unsigned short m_nUserSearchStringHash;
|
||||
mutable const char* m_pUserSearchString;
|
||||
|
||||
// stores the string data
|
||||
CUtlVector<StringPool_t*> m_StringPools;
|
||||
uint8 unknown[56];
|
||||
private:
|
||||
int FindPoolWithSpace( int len ) const;
|
||||
const char* StringFromIndex( const CStringPoolIndex &index ) const;
|
||||
const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const;
|
||||
|
||||
friend class CLess;
|
||||
friend class CSymbolHash;
|
||||
|
||||
};
|
||||
|
||||
class CUtlSymbolTableMT : public CUtlSymbolTable
|
||||
@ -195,25 +162,41 @@ public:
|
||||
|
||||
CUtlSymbol AddString( const char* pString, bool* created = NULL )
|
||||
{
|
||||
m_lock.LockForWrite();
|
||||
m_lock.LockForWrite( __FILE__, __LINE__ );
|
||||
CUtlSymbol result = CUtlSymbolTable::AddString( pString, created );
|
||||
m_lock.UnlockWrite();
|
||||
m_lock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return result;
|
||||
}
|
||||
|
||||
CUtlSymbol AddString( const char* pString, int nLength, bool* created = NULL )
|
||||
{
|
||||
m_lock.LockForWrite( __FILE__, __LINE__ );
|
||||
CUtlSymbol result = CUtlSymbolTable::AddString( pString, nLength, created );
|
||||
m_lock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return result;
|
||||
}
|
||||
|
||||
CUtlSymbol Find( const char* pString ) const
|
||||
{
|
||||
m_lock.LockForWrite();
|
||||
m_lock.LockForWrite( __FILE__, __LINE__ );
|
||||
CUtlSymbol result = CUtlSymbolTable::Find( pString );
|
||||
m_lock.UnlockWrite();
|
||||
m_lock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return result;
|
||||
}
|
||||
|
||||
CUtlSymbol Find( const char* pString, int nLength ) const
|
||||
{
|
||||
m_lock.LockForWrite( __FILE__, __LINE__ );
|
||||
CUtlSymbol result = CUtlSymbolTable::Find( pString, nLength );
|
||||
m_lock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* String( CUtlSymbol id ) const
|
||||
{
|
||||
m_lock.LockForRead();
|
||||
m_lock.LockForRead( __FILE__, __LINE__ );
|
||||
const char *pszResult = CUtlSymbolTable::String( id );
|
||||
m_lock.UnlockRead();
|
||||
m_lock.UnlockRead( __FILE__, __LINE__ );
|
||||
return pszResult;
|
||||
}
|
||||
|
||||
|
@ -313,11 +313,9 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT
|
||||
{
|
||||
unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength );
|
||||
|
||||
m_Mutex.Lock( __FILE__, __LINE__ );
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
sym = Find( hash, pString, nLength );
|
||||
|
||||
m_Mutex.Unlock( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
return sym;
|
||||
@ -341,14 +339,12 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT
|
||||
{
|
||||
unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength );
|
||||
|
||||
m_Mutex.Lock( __FILE__, __LINE__ );
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
sym = Find( hash, pString, nLength );
|
||||
|
||||
if ( !sym.IsValid() )
|
||||
sym = AddString( hash, pString, nLength, created );
|
||||
|
||||
m_Mutex.Unlock( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
return sym;
|
||||
@ -363,25 +359,21 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT
|
||||
template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE >
|
||||
inline void CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::RemoveAll()
|
||||
{
|
||||
m_Mutex.Lock( __FILE__, __LINE__ );
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
m_HashTable.RemoveAll();
|
||||
m_MemBlocks.RemoveAll();
|
||||
m_MemBlockAllocator.RemoveAll();
|
||||
|
||||
m_Mutex.Unlock( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE >
|
||||
inline void CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Purge()
|
||||
{
|
||||
m_Mutex.Lock( __FILE__, __LINE__ );
|
||||
AUTO_LOCK( m_Mutex );
|
||||
|
||||
m_HashTable.Purge();
|
||||
m_MemBlocks.Purge();
|
||||
m_MemBlockAllocator.Purge();
|
||||
|
||||
m_Mutex.Unlock( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
// Case-sensitive
|
||||
|
@ -54,18 +54,18 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template < int BUCKET_COUNT, class KEYTYPE = intp >
|
||||
template < class KEYTYPE = intp >
|
||||
class CUtlTSHashGenericHash
|
||||
{
|
||||
public:
|
||||
static int Hash( const KEYTYPE &key, int nBucketMask )
|
||||
{
|
||||
int nHash = HashIntConventional( (intp)key );
|
||||
if ( BUCKET_COUNT <= USHRT_MAX )
|
||||
if ( nBucketMask <= USHRT_MAX )
|
||||
{
|
||||
nHash ^= ( nHash >> 16 );
|
||||
}
|
||||
if ( BUCKET_COUNT <= UCHAR_MAX )
|
||||
if ( nBucketMask <= UCHAR_MAX )
|
||||
{
|
||||
nHash ^= ( nHash >> 8 );
|
||||
}
|
||||
@ -78,7 +78,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template < int BUCKET_COUNT, class KEYTYPE >
|
||||
template < class KEYTYPE >
|
||||
class CUtlTSHashUseKeyHashMethod
|
||||
{
|
||||
public:
|
||||
@ -94,7 +94,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template< class T, int BUCKET_COUNT, class KEYTYPE = intp, class HashFuncs = CUtlTSHashGenericHash< BUCKET_COUNT, KEYTYPE >, int nAlignment = 0 >
|
||||
template< class T, int BUCKET_COUNT, class KEYTYPE = intp, class HashFuncs = CUtlTSHashGenericHash< KEYTYPE > >
|
||||
class CUtlTSHash
|
||||
{
|
||||
public:
|
||||
@ -161,33 +161,28 @@ private:
|
||||
|
||||
struct HashBucket_t
|
||||
{
|
||||
CThreadSpinRWLock m_AddLock;
|
||||
HashFixedData_t *m_pFirst;
|
||||
HashFixedData_t *m_pFirstUncommitted;
|
||||
CThreadSpinRWLock m_AddLock;
|
||||
};
|
||||
|
||||
UtlTSHashHandle_t Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement );
|
||||
UtlTSHashHandle_t InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket );
|
||||
CMemoryPoolMT m_EntryMemory;
|
||||
CUtlMemoryPoolBase m_EntryMemory;
|
||||
HashBucket_t m_aBuckets[BUCKET_COUNT];
|
||||
bool m_bNeedsCommit;
|
||||
|
||||
#ifdef _DEBUG
|
||||
CInterlockedInt m_ContentionCheck;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::CUtlTSHash( int nAllocationCount ) :
|
||||
m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ), nAlignment )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::CUtlTSHash( int nAllocationCount ) :
|
||||
m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, alignof( HashFixedData_t ), UTLMEMORYPOOL_GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ) )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
m_ContentionCheck = 0;
|
||||
#endif
|
||||
m_bNeedsCommit = false;
|
||||
for ( int i = 0; i < BUCKET_COUNT; i++ )
|
||||
{
|
||||
@ -201,8 +196,8 @@ CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::CUtlTSHash( int nAlloca
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Deconstructor
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::~CUtlTSHash()
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::~CUtlTSHash()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ContentionCheck != 0 )
|
||||
@ -216,8 +211,8 @@ CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::~CUtlTSHash()
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destroy dynamically allocated hash data.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Purge( void )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Purge( void )
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
@ -226,8 +221,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Purge( void
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the number of elements in the hash table
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Count() const
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Count() const
|
||||
{
|
||||
return m_EntryMemory.Count();
|
||||
}
|
||||
@ -236,14 +231,14 @@ inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Count() cons
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns elements in the table
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const
|
||||
{
|
||||
int nIndex = 0;
|
||||
for ( int i = 0; i < BUCKET_COUNT; i++ )
|
||||
{
|
||||
const HashBucket_t &bucket = m_aBuckets[ i ];
|
||||
bucket.m_AddLock.LockForRead( );
|
||||
bucket.m_AddLock.LockForRead( __FILE__, __LINE__ );
|
||||
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
|
||||
{
|
||||
if ( --nFirstElement >= 0 )
|
||||
@ -252,11 +247,11 @@ int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nF
|
||||
pHandles[ nIndex++ ] = (UtlTSHashHandle_t)pElement;
|
||||
if ( nIndex >= nCount )
|
||||
{
|
||||
bucket.m_AddLock.UnlockRead( );
|
||||
bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
|
||||
return nIndex;
|
||||
}
|
||||
}
|
||||
bucket.m_AddLock.UnlockRead( );
|
||||
bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
|
||||
}
|
||||
return nIndex;
|
||||
}
|
||||
@ -266,8 +261,8 @@ int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nF
|
||||
// Purpose: Insert data into the hash table given its key (KEYTYPE),
|
||||
// without a check to see if the element already exists within the tree.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket )
|
||||
{
|
||||
m_bNeedsCommit = true;
|
||||
HashFixedData_t *pNewElement = static_cast< HashFixedData_t * >( m_EntryMemory.Alloc() );
|
||||
@ -282,8 +277,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
// Purpose: Insert data into the hash table given its key, with
|
||||
// a check to see if the element already exists within the tree.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ContentionCheck != 0 )
|
||||
@ -306,7 +301,7 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
return h;
|
||||
|
||||
// Now, try again, but only look in uncommitted elements
|
||||
bucket.m_AddLock.LockForWrite( );
|
||||
bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
|
||||
|
||||
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
|
||||
if ( h == InvalidHandle() )
|
||||
@ -319,12 +314,12 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
}
|
||||
}
|
||||
|
||||
bucket.m_AddLock.UnlockWrite( );
|
||||
bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return h;
|
||||
}
|
||||
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ContentionCheck != 0 )
|
||||
@ -346,7 +341,7 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
// Now, try again, but only look in uncommitted elements
|
||||
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
|
||||
HashBucket_t &bucket = m_aBuckets[ iBucket ];
|
||||
bucket.m_AddLock.LockForWrite( );
|
||||
bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
|
||||
|
||||
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
|
||||
if ( h == InvalidHandle() )
|
||||
@ -361,7 +356,7 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
}
|
||||
}
|
||||
|
||||
bucket.m_AddLock.UnlockWrite( );
|
||||
bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return h;
|
||||
}
|
||||
|
||||
@ -370,8 +365,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
// Purpose: Insert data into the hash table given its key
|
||||
// without a check to see if the element already exists within the tree.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, const T &data )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::FastInsert( KEYTYPE uiKey, const T &data )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ContentionCheck != 0 )
|
||||
@ -381,15 +376,15 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
#endif
|
||||
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
|
||||
HashBucket_t &bucket = m_aBuckets[ iBucket ];
|
||||
bucket.m_AddLock.LockForWrite( );
|
||||
bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
|
||||
UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
|
||||
CopyConstruct( &Element(h), data );
|
||||
bucket.m_AddLock.UnlockWrite( );
|
||||
bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return h;
|
||||
}
|
||||
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ContentionCheck != 0 )
|
||||
@ -399,10 +394,10 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
#endif
|
||||
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
|
||||
HashBucket_t &bucket = m_aBuckets[ iBucket ];
|
||||
bucket.m_AddLock.LockForWrite( );
|
||||
bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
|
||||
UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
|
||||
pConstructor->Construct( &Element(h) );
|
||||
bucket.m_AddLock.UnlockWrite( );
|
||||
bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
|
||||
return h;
|
||||
}
|
||||
|
||||
@ -410,8 +405,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Commits all uncommitted insertions
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Commit( )
|
||||
{
|
||||
// FIXME: Is this legal? Want this to be lock-free
|
||||
if ( !m_bNeedsCommit )
|
||||
@ -425,9 +420,9 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
|
||||
for ( int i = 0; i < BUCKET_COUNT; i++ )
|
||||
{
|
||||
HashBucket_t &bucket = m_aBuckets[ i ];
|
||||
bucket.m_AddLock.LockForRead( );
|
||||
bucket.m_AddLock.LockForRead( __FILE__, __LINE__ );
|
||||
bucket.m_pFirst = bucket.m_pFirstUncommitted;
|
||||
bucket.m_AddLock.UnlockRead( );
|
||||
bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
m_bNeedsCommit = false;
|
||||
@ -441,8 +436,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove a single element from the hash
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemove( KEYTYPE uiKey )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::FindAndRemove( KEYTYPE uiKey )
|
||||
{
|
||||
if ( m_EntryMemory.Count() == 0 )
|
||||
return;
|
||||
@ -454,7 +449,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemo
|
||||
|
||||
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
|
||||
HashBucket_t &bucket = m_aBuckets[ iBucket ];
|
||||
bucket.m_AddLock.LockForWrite( );
|
||||
bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
|
||||
|
||||
HashFixedData_t *pPrev = NULL;
|
||||
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext )
|
||||
@ -487,7 +482,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemo
|
||||
break;
|
||||
}
|
||||
|
||||
bucket.m_AddLock.UnlockWrite( );
|
||||
bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
|
||||
|
||||
#ifdef _DEBUG
|
||||
m_ContentionCheck--;
|
||||
@ -498,8 +493,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemo
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove all elements from the hash
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll( void )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::RemoveAll( void )
|
||||
{
|
||||
m_bNeedsCommit = false;
|
||||
if ( m_EntryMemory.Count() == 0 )
|
||||
@ -514,7 +509,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll(
|
||||
{
|
||||
HashBucket_t &bucket = m_aBuckets[ i ];
|
||||
|
||||
bucket.m_AddLock.LockForWrite( );
|
||||
bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
|
||||
|
||||
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
|
||||
{
|
||||
@ -523,7 +518,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll(
|
||||
|
||||
bucket.m_pFirst = NULL;
|
||||
bucket.m_pFirstUncommitted = NULL;
|
||||
bucket.m_AddLock.UnlockWrite( );
|
||||
bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
m_EntryMemory.Clear();
|
||||
@ -536,8 +531,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll(
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds an element, but only in the committed elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if ( m_ContentionCheck != 0 )
|
||||
@ -558,8 +553,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds an element, but only in the committed elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Find( KEYTYPE uiKey )
|
||||
{
|
||||
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
|
||||
const HashBucket_t &bucket = m_aBuckets[iBucket];
|
||||
@ -567,10 +562,13 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
if ( h != InvalidHandle() )
|
||||
return h;
|
||||
|
||||
// Didn't find it in the fast ( committed ) list. Let's try the slow ( uncommitted ) one
|
||||
bucket.m_AddLock.LockForRead( );
|
||||
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
|
||||
bucket.m_AddLock.UnlockRead( );
|
||||
if ( bucket.m_pFirstUncommitted && bucket.m_pFirstUncommitted != bucket.m_pFirst )
|
||||
{
|
||||
// Didn't find it in the fast ( committed ) list. Let's try the slow ( uncommitted ) one
|
||||
bucket.m_AddLock.LockForRead( __FILE__, __LINE__ );
|
||||
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
|
||||
bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
@ -579,41 +577,41 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return data given a hash handle.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Element( UtlTSHashHandle_t hHash )
|
||||
{
|
||||
return ((HashFixedData_t *)hHash)->m_Data;
|
||||
}
|
||||
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash ) const
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Element( UtlTSHashHandle_t hHash ) const
|
||||
{
|
||||
return ((HashFixedData_t *)hHash)->m_Data;
|
||||
}
|
||||
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash )
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::operator[]( UtlTSHashHandle_t hHash )
|
||||
{
|
||||
return ((HashFixedData_t *)hHash)->m_Data;
|
||||
}
|
||||
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash ) const
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::operator[]( UtlTSHashHandle_t hHash ) const
|
||||
{
|
||||
return ((HashFixedData_t *)hHash)->m_Data;
|
||||
}
|
||||
|
||||
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline KEYTYPE CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetID( UtlTSHashHandle_t hHash ) const
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline KEYTYPE CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::GetID( UtlTSHashHandle_t hHash ) const
|
||||
{
|
||||
return ((HashFixedData_t *)hHash)->m_uiKey;
|
||||
}
|
||||
|
||||
|
||||
// Convert element * to hashHandle
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::ElementPtrToHandle( T* pElement ) const
|
||||
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
|
||||
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::ElementPtrToHandle( T* pElement ) const
|
||||
{
|
||||
Assert( pElement );
|
||||
HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) );
|
||||
|
@ -1,316 +0,0 @@
|
||||
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "mempool.h"
|
||||
#include <stdio.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/malloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <memory.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include <ctype.h>
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
// Should be last include
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Error reporting... (debug only)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func )
|
||||
{
|
||||
g_ReportFunc = func;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment )
|
||||
{
|
||||
#ifdef _X360
|
||||
if( numElements > 0 && growMode != GROW_NONE )
|
||||
{
|
||||
numElements = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_nAlignment = ( nAlignment != 0 ) ? nAlignment : 1;
|
||||
Assert( IsPowerOfTwo( m_nAlignment ) );
|
||||
m_BlockSize = blockSize < (int)sizeof(void*) ? sizeof(void*) : blockSize;
|
||||
m_BlockSize = AlignValue( m_BlockSize, m_nAlignment );
|
||||
m_BlocksPerBlob = numElements;
|
||||
m_PeakAlloc = 0;
|
||||
m_GrowMode = growMode;
|
||||
if ( !pszAllocOwner )
|
||||
{
|
||||
pszAllocOwner = __FILE__;
|
||||
}
|
||||
m_pszAllocOwner = pszAllocOwner;
|
||||
Init();
|
||||
AddNewBlob();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees the memory contained in the mempool, and invalidates it for
|
||||
// any further use.
|
||||
// Input : *memPool - the mempool to shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlMemoryPool::~CUtlMemoryPool()
|
||||
{
|
||||
if (m_BlocksAllocated > 0)
|
||||
{
|
||||
ReportLeaks();
|
||||
}
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Resets the pool
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Init()
|
||||
{
|
||||
m_NumBlobs = 0;
|
||||
m_BlocksAllocated = 0;
|
||||
m_pHeadOfFreeList = 0;
|
||||
m_BlobHead.m_pNext = m_BlobHead.m_pPrev = &m_BlobHead;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Frees everything
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Clear()
|
||||
{
|
||||
// Free everything..
|
||||
CBlob *pNext;
|
||||
for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pNext )
|
||||
{
|
||||
pNext = pCur->m_pNext;
|
||||
free( pCur );
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reports memory leaks
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CUtlMemoryPool::ReportLeaks()
|
||||
{
|
||||
if (!g_ReportFunc)
|
||||
return;
|
||||
|
||||
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
|
||||
|
||||
#ifdef _DEBUG
|
||||
// walk and destroy the free list so it doesn't intefere in the scan
|
||||
while (m_pHeadOfFreeList != NULL)
|
||||
{
|
||||
void *next = *((void**)m_pHeadOfFreeList);
|
||||
memset(m_pHeadOfFreeList, 0, m_BlockSize);
|
||||
m_pHeadOfFreeList = next;
|
||||
}
|
||||
|
||||
g_ReportFunc("Dumping memory: \'");
|
||||
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
// scan the memory block and dump the leaks
|
||||
char *scanPoint = (char *)pCur->m_Data;
|
||||
char *scanEnd = pCur->m_Data + pCur->m_NumBytes;
|
||||
bool needSpace = false;
|
||||
|
||||
while (scanPoint < scanEnd)
|
||||
{
|
||||
// search for and dump any strings
|
||||
if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint))
|
||||
{
|
||||
g_ReportFunc("%c", *scanPoint);
|
||||
needSpace = true;
|
||||
}
|
||||
else if (needSpace)
|
||||
{
|
||||
needSpace = false;
|
||||
g_ReportFunc(" ");
|
||||
}
|
||||
|
||||
scanPoint++;
|
||||
}
|
||||
}
|
||||
|
||||
g_ReportFunc("\'\n");
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::AddNewBlob()
|
||||
{
|
||||
MEM_ALLOC_CREDIT_(m_pszAllocOwner);
|
||||
|
||||
int sizeMultiplier;
|
||||
|
||||
if( m_GrowMode == GROW_SLOW )
|
||||
{
|
||||
sizeMultiplier = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_GrowMode == GROW_NONE )
|
||||
{
|
||||
// Can only have one allocation when we're in this mode
|
||||
if( m_NumBlobs != 0 )
|
||||
{
|
||||
Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// GROW_FAST and GROW_NONE use this.
|
||||
sizeMultiplier = m_NumBlobs + 1;
|
||||
}
|
||||
|
||||
// maybe use something other than malloc?
|
||||
int nElements = m_BlocksPerBlob * sizeMultiplier;
|
||||
int blobSize = m_BlockSize * nElements;
|
||||
CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) );
|
||||
Assert( pBlob );
|
||||
|
||||
// Link it in at the end of the blob list.
|
||||
pBlob->m_NumBytes = blobSize;
|
||||
pBlob->m_pNext = &m_BlobHead;
|
||||
pBlob->m_pPrev = pBlob->m_pNext->m_pPrev;
|
||||
pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob;
|
||||
|
||||
// setup the free list
|
||||
m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment );
|
||||
Assert (m_pHeadOfFreeList);
|
||||
|
||||
void **newBlob = (void**)m_pHeadOfFreeList;
|
||||
for (int j = 0; j < nElements-1; j++)
|
||||
{
|
||||
newBlob[0] = (char*)newBlob + m_BlockSize;
|
||||
newBlob = (void**)newBlob[0];
|
||||
}
|
||||
|
||||
// null terminate list
|
||||
newBlob[0] = NULL;
|
||||
m_NumBlobs++;
|
||||
}
|
||||
|
||||
|
||||
void* CUtlMemoryPool::Alloc()
|
||||
{
|
||||
return Alloc( m_BlockSize );
|
||||
}
|
||||
|
||||
|
||||
void* CUtlMemoryPool::AllocZero()
|
||||
{
|
||||
return AllocZero( m_BlockSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocs a single block of memory from the pool.
|
||||
// Input : amount -
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CUtlMemoryPool::Alloc( size_t amount )
|
||||
{
|
||||
void *returnBlock;
|
||||
|
||||
if ( amount > (unsigned int)m_BlockSize )
|
||||
return NULL;
|
||||
|
||||
if( !m_pHeadOfFreeList )
|
||||
{
|
||||
// returning NULL is fine in GROW_NONE
|
||||
if( m_GrowMode == GROW_NONE )
|
||||
{
|
||||
//Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with GROW_NONE" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// overflow
|
||||
AddNewBlob();
|
||||
|
||||
// still failure, error out
|
||||
if( !m_pHeadOfFreeList )
|
||||
{
|
||||
Assert( !"CUtlMemoryPool::Alloc: ran out of memory" );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
m_BlocksAllocated++;
|
||||
m_PeakAlloc = MAX(m_PeakAlloc, m_BlocksAllocated);
|
||||
|
||||
returnBlock = m_pHeadOfFreeList;
|
||||
|
||||
// move the pointer the next block
|
||||
m_pHeadOfFreeList = *((void**)m_pHeadOfFreeList);
|
||||
|
||||
return returnBlock;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allocs a single block of memory from the pool, zeroes the memory before returning
|
||||
// Input : amount -
|
||||
//-----------------------------------------------------------------------------
|
||||
void *CUtlMemoryPool::AllocZero( size_t amount )
|
||||
{
|
||||
void *mem = Alloc( amount );
|
||||
if ( mem )
|
||||
{
|
||||
V_memset( mem, 0x00, amount );
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees a block of memory
|
||||
// Input : *memBlock - the memory to free
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlMemoryPool::Free( void *memBlock )
|
||||
{
|
||||
if ( !memBlock )
|
||||
return; // trying to delete NULL pointer, ignore
|
||||
|
||||
#ifdef _DEBUG
|
||||
// check to see if the memory is from the allocated range
|
||||
bool bOK = false;
|
||||
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
|
||||
{
|
||||
if (memBlock >= pCur->m_Data && (char*)memBlock < (pCur->m_Data + pCur->m_NumBytes))
|
||||
{
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
Assert (bOK);
|
||||
#endif // _DEBUG
|
||||
|
||||
#ifdef _DEBUG
|
||||
// invalidate the memory
|
||||
memset( memBlock, 0xDD, m_BlockSize );
|
||||
#endif
|
||||
|
||||
m_BlocksAllocated--;
|
||||
|
||||
// make the block point to the first item in the list
|
||||
*((void**)memBlock) = m_pHeadOfFreeList;
|
||||
|
||||
// the list head is now the new block
|
||||
m_pHeadOfFreeList = memBlock;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user