From ab21c7089619ce679eeae7e541dd68ac21cb69e6 Mon Sep 17 00:00:00 2001 From: vanz696 <152704532+vanz696@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:46:20 +0300 Subject: [PATCH] Add schemasystem (#215) Update CUtlMemoryPool*, CUtlSymbol*, CUtlTSHash, CThreadSpinRWLock, CThreadFastMutex (now replaced by CThreadSpinMutex) Implemented some missing ThreadInterlocked* functions --- public/entity2/entityclass.h | 8 +- public/entity2/entitycomponent.h | 7 +- public/entity2/entityinstance.h | 3 +- public/schemasystem/schemasystem.h | 221 ++++++++++++ public/schemasystem/schematypes.h | 427 ++++++++++++++++++++++ public/tier0/logging.h | 4 +- public/tier0/memalloc.h | 9 +- public/tier0/threadtools.h | 548 ++++++++++++++++------------- public/tier1/UtlStringMap.h | 4 +- public/tier1/memblockallocator.h | 4 +- public/tier1/mempool.h | 187 ++++------ public/tier1/utlsymbol.h | 165 ++++----- public/tier1/utlsymbollarge.h | 16 +- public/tier1/utltshash.h | 150 ++++---- tier1/mempool.cpp | 316 ----------------- 15 files changed, 1202 insertions(+), 867 deletions(-) create mode 100644 public/schemasystem/schemasystem.h create mode 100644 public/schemasystem/schematypes.h delete mode 100644 tier1/mempool.cpp diff --git a/public/entity2/entityclass.h b/public/entity2/entityclass.h index 832ccd3b..153e29ad 100644 --- a/public/entity2/entityclass.h +++ b/public/entity2/entityclass.h @@ -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; diff --git a/public/entity2/entitycomponent.h b/public/entity2/entitycomponent.h index e656e9da..ec39b69f 100644 --- a/public/entity2/entitycomponent.h +++ b/public/entity2/entitycomponent.h @@ -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 Schema_DynamicBinding() = 0; virtual void Finalize() = 0; - virtual void GetSchemaBinding(void**) = 0; + virtual SchemaMetaInfoHandle_t GetSchemaBinding() = 0; virtual datamap_t* GetDataDescMap() = 0; virtual bool Allocate( CEntityIdentity* pEntity, void* pComponent ) = 0; virtual void Free( CEntityIdentity* pEntity, void* pComponent ) = 0; diff --git a/public/entity2/entityinstance.h b/public/entity2/entityinstance.h index 433d9407..5160f18f 100644 --- a/public/entity2/entityinstance.h +++ b/public/entity2/entityinstance.h @@ -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 Schema_DynamicBinding() = 0; public: inline CEntityHandle GetRefEHandle() const diff --git a/public/schemasystem/schemasystem.h b/public/schemasystem/schemasystem.h new file mode 100644 index 00000000..1ee44cf0 --- /dev/null +++ b/public/schemasystem/schemasystem.h @@ -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 FindDeclaredClass( const char* pszClassName ) = 0; + virtual SchemaMetaInfoHandle_t FindDeclaredEnum( const char* pszEnumName ) = 0; + + virtual SchemaMetaInfoHandle_t FindBuiltinTypeByName( const char* pszBuiltinName ) = 0; + + virtual SchemaMetaInfoHandle_t Type_Builtin( SchemaBuiltinType_t eBuiltinType ) = 0; + virtual SchemaMetaInfoHandle_t Type_Ptr( CSchemaType* pObjectType ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic( const char* pszAtomicName, uint16 nSize, uint8 nAlignment ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic_T( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic_CollectionOfT( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, uint16 nElementSize, CSchemaType* pTemplateType, SchemaAtomicManipulatorFn_t manipulator ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic_TF( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, int nFuncPtrSize ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic_TT( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, CSchemaType* pTemplateType2 ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic_TTF( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, CSchemaType* pTemplateType2, int nFuncPtrSize ) = 0; + virtual SchemaMetaInfoHandle_t Type_Atomic_I( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, int nInterger ) = 0; + virtual SchemaMetaInfoHandle_t Type_DeclaredClass( const char* pszClassName ) = 0; + virtual SchemaMetaInfoHandle_t Type_DeclaredEnum( const char* pszEnumName ) = 0; + virtual SchemaMetaInfoHandle_t Type_FixedArray( CSchemaType* pElementType, int nElementCount, uint16 nElementSize, uint8 nElementAlignment ) = 0; + virtual SchemaMetaInfoHandle_t Type_FixedArray_Multidimensional( CSchemaType* pElementType, uint16 nElementSize, uint8 nElementAlignment, ... ) = 0; + virtual SchemaMetaInfoHandle_t Type_Bitfield( int nSize ) = 0; + + virtual SchemaMetaInfoHandle_t FindType_Atomic( int nAtomicID ) = 0; + virtual SchemaMetaInfoHandle_t FindType_Atomic_T( int nAtomicID, CSchemaType* pTemplateType ) = 0; + virtual SchemaMetaInfoHandle_t FindType_Atomic_CollectionOfT( int nAtomicID, CSchemaType* pTemplateType, SchemaAtomicManipulatorFn_t manipulator ) = 0; + virtual SchemaMetaInfoHandle_t FindType_Atomic_TF( int nAtomicID, CSchemaType* pTemplateType, int nFuncPtrSize ) = 0; + virtual SchemaMetaInfoHandle_t FindType_Atomic_TT( int nAtomicID, CSchemaType* pTemplateType, CSchemaType* pTemplateType2 ) = 0; + virtual SchemaMetaInfoHandle_t FindType_Atomic_TTF( int nAtomicID, CSchemaType* pTemplateType, CSchemaType* pTemplateType2, int nFuncPtrSize ) = 0; + virtual SchemaMetaInfoHandle_t 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 m_Ptrs; + CSchemaPtrMap m_Atomics; + CSchemaPtrMap m_AtomicsT; + CSchemaPtrMap m_AtomicsCollectionOfT; + CSchemaPtrMap m_AtomicsTF; + CSchemaPtrMap m_AtomicsTT; + CSchemaPtrMap m_AtomicsTTF; + CSchemaPtrMap m_AtomicsI; + CSchemaPtrMap m_DeclaredClasses; + CSchemaPtrMap m_DeclaredEnums; + CSchemaPtrMap m_AtomicInfos; + CSchemaPtrMap m_FixedArrays; + CSchemaPtrMap m_Bitfields; + + CUtlTSHash m_ClassBindings; + CUtlTSHash 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 FindClassByScopedName( const char* pszScopedName ) = 0; + virtual void ScopedNameForClass( const CSchemaClassInfo* pClassInfo, CBufferString& scopedName ) = 0; + + virtual SchemaMetaInfoHandle_t FindEnumByScopedName( const char* pszScopedName ) = 0; + virtual void ScopedNameForEnum( const CSchemaEnumInfo* pEnumInfo, CBufferString& scopedName ) = 0; + + virtual void FindDescendentsOfClass( const CSchemaClassInfo* pClassInfo, int, CUtlVector *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 *classes ) = 0; + + virtual void InstallCompleteModuleRegistrationCallback( CompleteModuleRegistrationCallbackFn_t pfnCallback, void* pArgument ) = 0; + virtual void RemoveCompleteModuleRegistrationCallback( CompleteModuleRegistrationCallbackFn_t pfnCallback, void* pArgument ) = 0; + + virtual SchemaMetaInfoHandle_t 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 m_ResourceManifestDescs; + int m_nNumConnections; + CThreadFastMutex m_Mutex; + +#ifdef CONVAR_WORK_FINISHED + CConCommandMemberAccessor m_SchemaListBindings; + CConCommandMemberAccessor m_SchemaAllListBindings; + CConCommandMemberAccessor m_SchemaDumpBinding; + CConCommandMemberAccessor m_SchemaDetailedClassLayout; + CConCommandMemberAccessor m_SchemaStats; + CConCommandMemberAccessor m_SchemaMetaStats; +#else +#ifdef _WIN32 + uint8 pad[288]; +#else + uint8 pad[384]; +#endif // _WIN32 +#endif // CONVAR_WORK_FINISHED + + CUtlVector m_LoadedModules; + CUtlVector m_DetectedSchemaMismatches; + + bool m_bDefaultTypeScopeIsLocal; + bool m_bSchemaSystemIsReady; + + CUtlStringMap m_TypeScopes; + CUtlStringMap m_BindingsAddressRanges; + + int m_nRegistrations; + int m_nIgnored; + int m_nRedundant; + size_t m_nIgnoredBytes; + + CUtlVector m_CompleteModuleRegistrationCallbacks; +}; + +#endif // SCHEMASYSTEM_H diff --git a/public/schemasystem/schematypes.h b/public/schemasystem/schematypes.h new file mode 100644 index 00000000..32af335c --- /dev/null +++ b/public/schemasystem/schematypes.h @@ -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 +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 CSchemaPtrMap +{ +public: + CUtlMap 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 GetInnerType() { return SchemaMetaInfoHandle_t(); } + virtual SchemaMetaInfoHandle_t GetInnermostType() { return SchemaMetaInfoHandle_t(); } + 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 diff --git a/public/tier0/logging.h b/public/tier0/logging.h index da4978cc..ac95ef6b 100644 --- a/public/tier0/logging.h +++ b/public/tier0/logging.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. diff --git a/public/tier0/memalloc.h b/public/tier0/memalloc.h index 0d6c0564..989e31b3 100644 --- a/public/tier0/memalloc.h +++ b/public/tier0/memalloc.h @@ -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 diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index 4a8933e7..1536371a 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -14,6 +14,10 @@ #include "tier0/platform.h" #include "tier0/dbg.h" +#ifdef PLATFORM_WINDOWS_PC +#include +#endif + #ifdef POSIX #include #include @@ -38,10 +42,6 @@ #pragma warning(disable:4251) #endif -#ifdef COMPILER_MSVC64 -#include -#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 _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(p), reinterpret_cast(value) ) ); } -inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) ); } -inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast(p), reinterpret_cast(value), reinterpret_cast(comperand) ) == reinterpret_cast(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 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(this))->Lock( pFileName, nLine ); } - void Unlock( const char *pFileName, int nLine ); - void Unlock( const char *pFileName, int nLine ) const { (const_cast(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(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(this))->Unlock( pFileName, nLine ); } - bool TryLock( const char *pFileName, int nLine ); - bool TryLock( const char *pFileName, int nLine ) const { return (const_cast(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(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(this))->TryLock(); } - void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast(this))->Lock( nSpinSleepTime ); } - void Unlock() const volatile { (const_cast(this))->Unlock(); } + bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const volatile { return (const_cast(this))->TryLock( pFileName, nLine ); } + void Lock( const char *pFileName = NULL, int nLine = -1, unsigned nSpinSleepTime = 0 ) const volatile { (const_cast(this))->Lock( pFileName, nLine, nSpinSleepTime ); } + void Unlock( const char *pFileName = NULL, int nLine = -1 ) const volatile { (const_cast(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 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 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 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(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 & ); - CAutoLockT &operator=( const CAutoLockT & ); + CAutoLockT( const CAutoLockT & ); + CAutoLockT &operator=( const CAutoLockT & ); }; typedef CAutoLockT CAutoLock; //--------------------------------------------------------- -template struct CAutoLockTypeDeducer {}; -template <> struct CAutoLockTypeDeducer { typedef CThreadMutex Type_t; }; -template <> struct CAutoLockTypeDeducer { typedef CThreadNullMutex Type_t; }; -#if !defined(THREAD_PROFILER) -template <> struct CAutoLockTypeDeducer { typedef CThreadFastMutex Type_t; }; -template <> struct CAutoLockTypeDeducer { typedef CAlignedThreadFastMutex Type_t; }; -#endif - #define AUTO_LOCK_( type, mutex ) \ - CAutoLockT< type > UNIQUE_ID( static_cast( mutex ) ) + CAutoLockT< type > UNIQUE_ID( static_cast( mutex ), __FILE__, __LINE__ ) -#ifdef COMPILER_GCC -#define AUTO_LOCK( mutex ) \ - AUTO_LOCK_( typename CAutoLockTypeDeducer::Type_t, mutex ) -#else -#define AUTO_LOCK( mutex ) \ - AUTO_LOCK_( CAutoLockTypeDeducer::Type_t, mutex ) -#endif +template T strip_cv_quals_for_mutex(T&); +template T strip_cv_quals_for_mutex(const T&); +template T strip_cv_quals_for_mutex(volatile T&); +template 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(this)->TryLockForWrite(); } - bool TryLockForRead() const { return const_cast(this)->TryLockForRead(); } - void LockForRead() const { const_cast(this)->LockForRead(); } - void UnlockRead() const { const_cast(this)->UnlockRead(); } - void LockForWrite() const { const_cast(this)->LockForWrite(); } - void UnlockWrite() const { const_cast(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(this)->TryLockForWrite( pFileName, nLine ); } + bool TryLockForRead( const char *pFileName = NULL, int nLine = -1 ) const { return const_cast(this)->TryLockForRead( pFileName, nLine ); } + + void LockForRead( const char *pFileName = NULL, int nLine = -1 ) const { const_cast(this)->LockForRead( pFileName, nLine ); } + void UnlockRead( const char *pFileName = NULL, int nLine = -1 ) const { const_cast(this)->UnlockRead( pFileName, nLine ); } + void LockForWrite( const char *pFileName = NULL, int nLine = -1 ) const { const_cast(this)->LockForWrite( pFileName, nLine ); } + void UnlockWrite( const char *pFileName = NULL, int nLine = -1 ) const { const_cast(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 ); } } diff --git a/public/tier1/UtlStringMap.h b/public/tier1/UtlStringMap.h index ee60c850..191da123 100644 --- a/public/tier1/UtlStringMap.h +++ b/public/tier1/UtlStringMap.h @@ -16,7 +16,9 @@ template 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 ) { } diff --git a/public/tier1/memblockallocator.h b/public/tier1/memblockallocator.h index 4f609dd9..222a9ffa 100644 --- a/public/tier1/memblockallocator.h +++ b/public/tier1/memblockallocator.h @@ -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 { diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h index c475c61f..f52f52e3 100644 --- a/public/tier1/mempool.h +++ b/public/tier1/mempool.h @@ -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; + + //----------------------------------------------------------------------------- // Specialized pool for aligned data management (e.g., Xbox textures) //----------------------------------------------------------------------------- @@ -317,13 +305,13 @@ public: template< class T > -inline T* CClassMemoryPool::Alloc() +inline T* CUtlMemoryPool::Alloc() { T *pRet; { MEM_ALLOC_CREDIT_CLASS(); - pRet = (T*)CUtlMemoryPool::Alloc(); + pRet = (T*)CUtlMemoryPoolBase::Alloc(); } if ( pRet ) @@ -334,13 +322,13 @@ inline T* CClassMemoryPool::Alloc() } template< class T > -inline T* CClassMemoryPool::AllocZero() +inline T* CUtlMemoryPool::AllocZero() { T *pRet; { MEM_ALLOC_CREDIT_CLASS(); - pRet = (T*)CUtlMemoryPool::AllocZero(); + pRet = (T*)CUtlMemoryPoolBase::AllocZero(); } if ( pRet ) @@ -351,44 +339,20 @@ inline T* CClassMemoryPool::AllocZero() } template< class T > -inline void CClassMemoryPool::Free(T *pMem) +inline void CUtlMemoryPool::Free(T *pMem) { if ( pMem ) { Destruct( pMem ); } - CUtlMemoryPool::Free( pMem ); + CUtlMemoryPoolBase::Free( pMem ); } template< class T > -inline void CClassMemoryPool::Clear() +inline void CUtlMemoryPool::Clear() { - CUtlRBTree 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 ); } @@ -399,30 +363,27 @@ inline void CClassMemoryPool::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::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 diff --git a/public/tier1/utlsymbol.h b/public/tier1/utlsymbol.h index 0c23f12f..9862db52 100644 --- a/public/tier1/utlsymbol.h +++ b/public/tier1/utlsymbol.h @@ -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 - { - public: - CTree( int growSize, int initSize ) : CUtlRBTree( growSize, initSize ) {} - friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table - }; + typedef CUtlHashtable Hashtable_t; + typedef CUtlVector 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 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; } diff --git a/public/tier1/utlsymbollarge.h b/public/tier1/utlsymbollarge.h index 788c36ba..0e839bb4 100644 --- a/public/tier1/utlsymbollarge.h +++ b/public/tier1/utlsymbollarge.h @@ -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 diff --git a/public/tier1/utltshash.h b/public/tier1/utltshash.h index 05114656..d033d8dc 100644 --- a/public/tier1/utltshash.h +++ b/public/tier1/utltshash.h @@ -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 -CUtlTSHash::CUtlTSHash( int nAllocationCount ) : - m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ), nAlignment ) +template +CUtlTSHash::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::CUtlTSHash( int nAlloca //----------------------------------------------------------------------------- // Purpose: Deconstructor //----------------------------------------------------------------------------- -template -CUtlTSHash::~CUtlTSHash() +template +CUtlTSHash::~CUtlTSHash() { #ifdef _DEBUG if ( m_ContentionCheck != 0 ) @@ -216,8 +211,8 @@ CUtlTSHash::~CUtlTSHash() //----------------------------------------------------------------------------- // Purpose: Destroy dynamically allocated hash data. //----------------------------------------------------------------------------- -template -inline void CUtlTSHash::Purge( void ) +template +inline void CUtlTSHash::Purge( void ) { RemoveAll(); } @@ -226,8 +221,8 @@ inline void CUtlTSHash::Purge( void //----------------------------------------------------------------------------- // Returns the number of elements in the hash table //----------------------------------------------------------------------------- -template -inline int CUtlTSHash::Count() const +template +inline int CUtlTSHash::Count() const { return m_EntryMemory.Count(); } @@ -236,14 +231,14 @@ inline int CUtlTSHash::Count() cons //----------------------------------------------------------------------------- // Returns elements in the table //----------------------------------------------------------------------------- -template -int CUtlTSHash::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const +template +int CUtlTSHash::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::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::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 -inline UtlTSHashHandle_t CUtlTSHash::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket ) +template +inline UtlTSHashHandle_t CUtlTSHash::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 // Purpose: Insert data into the hash table given its key, with // a check to see if the element already exists within the tree. //----------------------------------------------------------------------------- -template -inline UtlTSHashHandle_t CUtlTSHash::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert ) +template +inline UtlTSHashHandle_t CUtlTSHash::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert ) { #ifdef _DEBUG if ( m_ContentionCheck != 0 ) @@ -306,7 +301,7 @@ inline UtlTSHashHandle_t CUtlTSHash 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 } } - bucket.m_AddLock.UnlockWrite( ); + bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ ); return h; } -template -inline UtlTSHashHandle_t CUtlTSHash::Insert( KEYTYPE uiKey, ITSHashConstructor *pConstructor, bool *pDidInsert ) +template +inline UtlTSHashHandle_t CUtlTSHash::Insert( KEYTYPE uiKey, ITSHashConstructor *pConstructor, bool *pDidInsert ) { #ifdef _DEBUG if ( m_ContentionCheck != 0 ) @@ -346,7 +341,7 @@ inline UtlTSHashHandle_t CUtlTSHash // 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 } } - bucket.m_AddLock.UnlockWrite( ); + bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ ); return h; } @@ -370,8 +365,8 @@ inline UtlTSHashHandle_t CUtlTSHash // Purpose: Insert data into the hash table given its key // without a check to see if the element already exists within the tree. //----------------------------------------------------------------------------- -template -inline UtlTSHashHandle_t CUtlTSHash::FastInsert( KEYTYPE uiKey, const T &data ) +template +inline UtlTSHashHandle_t CUtlTSHash::FastInsert( KEYTYPE uiKey, const T &data ) { #ifdef _DEBUG if ( m_ContentionCheck != 0 ) @@ -381,15 +376,15 @@ inline UtlTSHashHandle_t CUtlTSHash #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 -inline UtlTSHashHandle_t CUtlTSHash::FastInsert( KEYTYPE uiKey, ITSHashConstructor *pConstructor ) +template +inline UtlTSHashHandle_t CUtlTSHash::FastInsert( KEYTYPE uiKey, ITSHashConstructor *pConstructor ) { #ifdef _DEBUG if ( m_ContentionCheck != 0 ) @@ -399,10 +394,10 @@ inline UtlTSHashHandle_t CUtlTSHash #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 //----------------------------------------------------------------------------- // Purpose: Commits all uncommitted insertions //----------------------------------------------------------------------------- -template -inline void CUtlTSHash::Commit( ) +template +inline void CUtlTSHash::Commit( ) { // FIXME: Is this legal? Want this to be lock-free if ( !m_bNeedsCommit ) @@ -425,9 +420,9 @@ inline void CUtlTSHash::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::Commit( ) //----------------------------------------------------------------------------- // Purpose: Remove a single element from the hash //----------------------------------------------------------------------------- -template -inline void CUtlTSHash::FindAndRemove( KEYTYPE uiKey ) +template +inline void CUtlTSHash::FindAndRemove( KEYTYPE uiKey ) { if ( m_EntryMemory.Count() == 0 ) return; @@ -454,7 +449,7 @@ inline void CUtlTSHash::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::FindAndRemo break; } - bucket.m_AddLock.UnlockWrite( ); + bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ ); #ifdef _DEBUG m_ContentionCheck--; @@ -498,8 +493,8 @@ inline void CUtlTSHash::FindAndRemo //----------------------------------------------------------------------------- // Purpose: Remove all elements from the hash //----------------------------------------------------------------------------- -template -inline void CUtlTSHash::RemoveAll( void ) +template +inline void CUtlTSHash::RemoveAll( void ) { m_bNeedsCommit = false; if ( m_EntryMemory.Count() == 0 ) @@ -514,7 +509,7 @@ inline void CUtlTSHash::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::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::RemoveAll( //----------------------------------------------------------------------------- // Finds an element, but only in the committed elements //----------------------------------------------------------------------------- -template -inline UtlTSHashHandle_t CUtlTSHash::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement ) +template +inline UtlTSHashHandle_t CUtlTSHash::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement ) { #ifdef _DEBUG if ( m_ContentionCheck != 0 ) @@ -558,8 +553,8 @@ inline UtlTSHashHandle_t CUtlTSHash //----------------------------------------------------------------------------- // Finds an element, but only in the committed elements //----------------------------------------------------------------------------- -template -inline UtlTSHashHandle_t CUtlTSHash::Find( KEYTYPE uiKey ) +template +inline UtlTSHashHandle_t CUtlTSHash::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 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 //----------------------------------------------------------------------------- // Purpose: Return data given a hash handle. //----------------------------------------------------------------------------- -template -inline T &CUtlTSHash::Element( UtlTSHashHandle_t hHash ) +template +inline T &CUtlTSHash::Element( UtlTSHashHandle_t hHash ) { return ((HashFixedData_t *)hHash)->m_Data; } -template -inline T const &CUtlTSHash::Element( UtlTSHashHandle_t hHash ) const +template +inline T const &CUtlTSHash::Element( UtlTSHashHandle_t hHash ) const { return ((HashFixedData_t *)hHash)->m_Data; } -template -inline T &CUtlTSHash::operator[]( UtlTSHashHandle_t hHash ) +template +inline T &CUtlTSHash::operator[]( UtlTSHashHandle_t hHash ) { return ((HashFixedData_t *)hHash)->m_Data; } -template -inline T const &CUtlTSHash::operator[]( UtlTSHashHandle_t hHash ) const +template +inline T const &CUtlTSHash::operator[]( UtlTSHashHandle_t hHash ) const { return ((HashFixedData_t *)hHash)->m_Data; } -template -inline KEYTYPE CUtlTSHash::GetID( UtlTSHashHandle_t hHash ) const +template +inline KEYTYPE CUtlTSHash::GetID( UtlTSHashHandle_t hHash ) const { return ((HashFixedData_t *)hHash)->m_uiKey; } // Convert element * to hashHandle -template -inline UtlTSHashHandle_t CUtlTSHash::ElementPtrToHandle( T* pElement ) const +template +inline UtlTSHashHandle_t CUtlTSHash::ElementPtrToHandle( T* pElement ) const { Assert( pElement ); HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) ); diff --git a/tier1/mempool.cpp b/tier1/mempool.cpp deleted file mode 100644 index 8a69a0ea..00000000 --- a/tier1/mempool.cpp +++ /dev/null @@ -1,316 +0,0 @@ -//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// -// -// Purpose: -// -//===========================================================================// - -#include "mempool.h" -#include -#ifdef __APPLE__ -#include -#else -#include -#endif -#include -#include "tier0/dbg.h" -#include -#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; -} - -