1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-09-20 04:26:03 +08:00

Add schemasystem (#215)

Update CUtlMemoryPool*, CUtlSymbol*, CUtlTSHash, CThreadSpinRWLock, CThreadFastMutex (now replaced by CThreadSpinMutex)

Implemented some missing ThreadInterlocked* functions
This commit is contained in:
vanz696
2024-03-18 15:46:20 +03:00
committed by GitHub
parent 79d4cb7da3
commit ab21c70896
15 changed files with 1202 additions and 867 deletions

View File

@ -23,6 +23,7 @@
#define FENTCLASS_UNK009 (1 << 9) #define FENTCLASS_UNK009 (1 << 9)
#define FENTCLASS_FORCE_WORLDGROUPID (1 << 10) // Forces worldgroupid to be 1 on created entities #define FENTCLASS_FORCE_WORLDGROUPID (1 << 10) // Forces worldgroupid to be 1 on created entities
class CSchemaClassInfo;
class CEntityClass; class CEntityClass;
class CEntityIdentity; class CEntityIdentity;
class ServerClass; class ServerClass;
@ -44,7 +45,7 @@ public:
const char* m_pszDescription; const char* m_pszDescription;
CEntityClass *m_pClass; CEntityClass *m_pClass;
CEntityClassInfo *m_pBaseClassInfo; CEntityClassInfo *m_pBaseClassInfo;
void* m_pSchemaBinding; CSchemaClassInfo* m_pSchemaBinding;
datamap_t* m_pDataDescMap; datamap_t* m_pDataDescMap;
datamap_t* m_pPredDescMap; datamap_t* m_pPredDescMap;
}; };
@ -76,6 +77,11 @@ class CEntityClass
}; };
public: public:
inline CSchemaClassInfo *GetSchemaBinding() const
{
return m_pClassInfo->m_pSchemaBinding;
}
inline datamap_t *GetDataDescMap() const inline datamap_t *GetDataDescMap() const
{ {
return m_pClassInfo->m_pDataDescMap; return m_pClassInfo->m_pDataDescMap;

View File

@ -9,6 +9,7 @@
#include "tier1/utlsymbollarge.h" #include "tier1/utlsymbollarge.h"
#include "tier1/utlstring.h" #include "tier1/utlstring.h"
#include "datamap.h" #include "datamap.h"
#include "schemasystem/schematypes.h"
class CEntityIdentity; class CEntityIdentity;
class CEntityComponentHelper; class CEntityComponentHelper;
@ -22,7 +23,7 @@ struct ComponentUnserializerKeyNamesChunk_t
struct ComponentUnserializerFieldInfo_t struct ComponentUnserializerFieldInfo_t
{ {
void* m_pSchemaEnum; CSchemaEnumInfo* m_pSchemaEnum;
const char* m_pKeyName; const char* m_pKeyName;
uint16 m_nOffset; uint16 m_nOffset;
@ -72,9 +73,9 @@ struct EntComponentInfo_t
class CEntityComponentHelper class CEntityComponentHelper
{ {
public: public:
virtual void Schema_DynamicBinding(void**) = 0; virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> Schema_DynamicBinding() = 0;
virtual void Finalize() = 0; virtual void Finalize() = 0;
virtual void GetSchemaBinding(void**) = 0; virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> GetSchemaBinding() = 0;
virtual datamap_t* GetDataDescMap() = 0; virtual datamap_t* GetDataDescMap() = 0;
virtual bool Allocate( CEntityIdentity* pEntity, void* pComponent ) = 0; virtual bool Allocate( CEntityIdentity* pEntity, void* pComponent ) = 0;
virtual void Free( CEntityIdentity* pEntity, void* pComponent ) = 0; virtual void Free( CEntityIdentity* pEntity, void* pComponent ) = 0;

View File

@ -8,6 +8,7 @@
#include "entity2/entitycomponent.h" #include "entity2/entitycomponent.h"
#include "entity2/entityidentity.h" #include "entity2/entityidentity.h"
#include "variant.h" #include "variant.h"
#include "schemasystem/schematypes.h"
class CEntityKeyValues; class CEntityKeyValues;
class CFieldPath; class CFieldPath;
@ -77,7 +78,7 @@ public:
virtual void ReloadPrivateScripts() = 0; virtual void ReloadPrivateScripts() = 0;
virtual datamap_t* GetDataDescMap() = 0; virtual datamap_t* GetDataDescMap() = 0;
virtual void unk201() = 0; virtual void unk201() = 0;
virtual void Schema_DynamicBinding(void**) = 0; virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> Schema_DynamicBinding() = 0;
public: public:
inline CEntityHandle GetRefEHandle() const inline CEntityHandle GetRefEHandle() const

View File

@ -0,0 +1,221 @@
#ifndef SCHEMASYSTEM_H
#define SCHEMASYSTEM_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/threadtools.h"
#include "tier1/convar.h"
#include "tier1/utlstring.h"
#include "tier1/UtlStringMap.h"
#include "tier1/utltshash.h"
#include "tier1/utlvector.h"
#include "appframework/IAppSystem.h"
#include "schemasystem/schematypes.h"
class CBufferString;
class CKeyValues3Context;
struct ResourceManifestDesc_t;
enum SchemaTypeScope_t : uint8
{
SCHEMA_TYPESCOPE_GLOBAL = 0,
SCHEMA_TYPESCOPE_LOCAL,
SCHEMA_TYPESCOPE_DEFAULT,
};
typedef void (*CompleteModuleRegistrationCallbackFn_t)(void*);
abstract_class ISchemaSystemTypeScope
{
public:
virtual CSchemaClassInfo* InstallSchemaClassBinding( const char* pszModuleName, CSchemaClassInfo* pClassInfo ) = 0;
virtual CSchemaEnumInfo* InstallSchemaEnumBinding( const char* pszModuleName, CSchemaEnumInfo* pEnumInfo ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> FindDeclaredClass( const char* pszClassName ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaEnumInfo> FindDeclaredEnum( const char* pszEnumName ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Builtin> FindBuiltinTypeByName( const char* pszBuiltinName ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Builtin> Type_Builtin( SchemaBuiltinType_t eBuiltinType ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Ptr> Type_Ptr( CSchemaType* pObjectType ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic> Type_Atomic( const char* pszAtomicName, uint16 nSize, uint8 nAlignment ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_T> Type_Atomic_T( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_CollectionOfT> Type_Atomic_CollectionOfT( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, uint16 nElementSize, CSchemaType* pTemplateType, SchemaAtomicManipulatorFn_t manipulator ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TF> Type_Atomic_TF( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, int nFuncPtrSize ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TT> Type_Atomic_TT( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, CSchemaType* pTemplateType2 ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TTF> Type_Atomic_TTF( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, CSchemaType* pTemplateType, CSchemaType* pTemplateType2, int nFuncPtrSize ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_I> Type_Atomic_I( const char* pszAtomicName, uint16 nSize, uint8 nAlignment, int nInterger ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_DeclaredClass> Type_DeclaredClass( const char* pszClassName ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_DeclaredEnum> Type_DeclaredEnum( const char* pszEnumName ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_FixedArray> Type_FixedArray( CSchemaType* pElementType, int nElementCount, uint16 nElementSize, uint8 nElementAlignment ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_FixedArray> Type_FixedArray_Multidimensional( CSchemaType* pElementType, uint16 nElementSize, uint8 nElementAlignment, ... ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Bitfield> Type_Bitfield( int nSize ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic> FindType_Atomic( int nAtomicID ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_T> FindType_Atomic_T( int nAtomicID, CSchemaType* pTemplateType ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_CollectionOfT> FindType_Atomic_CollectionOfT( int nAtomicID, CSchemaType* pTemplateType, SchemaAtomicManipulatorFn_t manipulator ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TF> FindType_Atomic_TF( int nAtomicID, CSchemaType* pTemplateType, int nFuncPtrSize ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TT> FindType_Atomic_TT( int nAtomicID, CSchemaType* pTemplateType, CSchemaType* pTemplateType2 ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_TTF> FindType_Atomic_TTF( int nAtomicID, CSchemaType* pTemplateType, CSchemaType* pTemplateType2, int nFuncPtrSize ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Atomic_I> FindType_Atomic_I( int nAtomicID, int nInteger ) = 0;
virtual CSchemaType_DeclaredClass* FindType_DeclaredClass( const char* pszClassName ) = 0;
virtual CSchemaType_DeclaredEnum* FindType_DeclaredEnum( const char* pszEnumName ) = 0;
virtual CSchemaClassInfo* FindRawClassBinding( const char* pszClassName ) = 0;
virtual CSchemaClassInfo* FindRawClassBinding( uint nClassID ) = 0;
virtual CSchemaEnumInfo* FindRawEnumBinding( const char* pszEnumName ) = 0;
virtual CSchemaEnumInfo* FindRawEnumBinding( uint nEnumID ) = 0;
virtual const char* GetScopeName() = 0;
virtual bool IsGlobalScope() = 0;
virtual void MarkClassAsRequiringGlobalPromotion( const CSchemaClassInfo* pClassInfo ) = 0;
virtual void MarkEnumAsRequiringGlobalPromotion( const CSchemaEnumInfo* pEnumInfo ) = 0;
virtual void ResolveAtomicInfoThreadsafe( const SchemaAtomicTypeInfo_t** ppAtomicInfo, const char* pszAtomicName, int nAtomicID ) = 0;
virtual void ResolveEnumInfoThreadsafe( const CSchemaEnumInfo** pEnumInfo, const char* pszEnumName ) = 0;
virtual void ResolveClassInfoThreadsafe( const CSchemaClassInfo** pClassInfo, const char* pszClassName ) = 0;
};
class CSchemaSystemTypeScope : public ISchemaSystemTypeScope
{
public:
char m_szScopeName[256];
CSchemaSystemTypeScope* m_pGlobalTypeScope;
bool m_bBuiltinTypesInitialized;
CSchemaType_Builtin m_BuiltinTypes[SCHEMA_BUILTIN_COUNT];
CSchemaPtrMap<CSchemaType*, CSchemaType_Ptr*> m_Ptrs;
CSchemaPtrMap<int, CSchemaType_Atomic*> m_Atomics;
CSchemaPtrMap<AtomicTypeInfo_T_t, CSchemaType_Atomic_T*> m_AtomicsT;
CSchemaPtrMap<AtomicTypeInfo_T_t, CSchemaType_Atomic_CollectionOfT*> m_AtomicsCollectionOfT;
CSchemaPtrMap<AtomicTypeInfo_TF_t, CSchemaType_Atomic_TF*> m_AtomicsTF;
CSchemaPtrMap<AtomicTypeInfo_TT_t, CSchemaType_Atomic_TT*> m_AtomicsTT;
CSchemaPtrMap<AtomicTypeInfo_TTF_t, CSchemaType_Atomic_TTF*> m_AtomicsTTF;
CSchemaPtrMap<AtomicTypeInfo_I_t, CSchemaType_Atomic_I*> m_AtomicsI;
CSchemaPtrMap<uint, CSchemaType_DeclaredClass*> m_DeclaredClasses;
CSchemaPtrMap<uint, CSchemaType_DeclaredEnum*> m_DeclaredEnums;
CSchemaPtrMap<int, const SchemaAtomicTypeInfo_t*> m_AtomicInfos;
CSchemaPtrMap<TypeAndCountInfo_t, CSchemaType_FixedArray*> m_FixedArrays;
CSchemaPtrMap<int, CSchemaType_Bitfield*> m_Bitfields;
CUtlTSHash<CSchemaClassInfo*, 256, uint> m_ClassBindings;
CUtlTSHash<CSchemaEnumInfo*, 256, uint> m_EnumBindings;
};
#define SCHEMASYSTEM_INTERFACE_VERSION "SchemaSystem_001"
abstract_class ISchemaSystem : public IAppSystem
{
public:
virtual CSchemaSystemTypeScope* GlobalTypeScope() = 0;
virtual CSchemaSystemTypeScope* FindOrCreateTypeScopeForModule( const char* pszModuleName, const char** ppszBindingName = NULL ) = 0;
virtual CSchemaSystemTypeScope* FindTypeScopeForModule( const char* pszModuleName, const char** ppszBindingName = NULL ) = 0;
virtual CSchemaSystemTypeScope* GetTypeScopeForBinding( SchemaTypeScope_t eTypeScope, const char* pszModuleName, const char** ppszBindingName = NULL ) = 0;
virtual bool DefaultTypeScopeIsLocal() = 0;
virtual SchemaMetaInfoHandle_t<CSchemaClassInfo> FindClassByScopedName( const char* pszScopedName ) = 0;
virtual void ScopedNameForClass( const CSchemaClassInfo* pClassInfo, CBufferString& scopedName ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaEnumInfo> FindEnumByScopedName( const char* pszScopedName ) = 0;
virtual void ScopedNameForEnum( const CSchemaEnumInfo* pEnumInfo, CBufferString& scopedName ) = 0;
virtual void FindDescendentsOfClass( const CSchemaClassInfo* pClassInfo, int, CUtlVector<const CSchemaClassInfo*> *descendents, bool ) = 0;
virtual void LoadSchemaDataForModules( const char** ppszModules, int nModules ) = 0;
virtual const char* GetClassModuleName( const CSchemaClassInfo* pClassInfo ) = 0;
virtual const char* GetClassProjectName( const CSchemaClassInfo* pClassInfo ) = 0;
virtual const char* GetEnumModuleName( const CSchemaEnumInfo* pEnumInfo ) = 0;
virtual const char* GetEnumProjectName( const CSchemaEnumInfo* pEnumInfo ) = 0;
virtual bool SchemaSystemIsReady() = 0;
virtual void VerifySchemaBindingConsistency( bool ) = 0;
virtual void CompleteModuleRegistration( const char* pszModuleName ) = 0;
virtual void RegisterAtomicType( const SchemaAtomicTypeInfo_t* pAtomicType ) = 0;
virtual void PrintSchemaStats( const char* pszOptions ) = 0;
virtual void PrintSchemaMetaStats( const char* pszOptions ) = 0;
virtual void RegisterAtomics( const char* pszModuleName, const char* pszProjectName, CSchemaType** ppSchemaTypes, int, SchemaAtomicTypeInfo_t** ppAtomicTypes ) = 0;
virtual void RegisterEnums( const char* pszModuleName, const char* pszProjectName, CSchemaType** ppSchemaTypes, int, CSchemaEnumInfo** ppEnumInfos ) = 0;
virtual bool RegisterClasses( const char* pszModuleName, const char* pszProjectName, CSchemaType** ppSchemaTypes, int, CSchemaClassInfo** ppClassInfos, CBufferString* pErrorStr ) = 0;
virtual void ValidateClasses( CSchemaClassInfo** ppClassInfos ) = 0;
virtual bool ConvertOldIntrospectedResourceDataToKV3( void*, void*, void*, CKeyValues3Context*, const char* ) = 0;
virtual void FindClassesByMeta( const char* pszMetaName, int, CUtlVector<const CSchemaClassInfo*> *classes ) = 0;
virtual void InstallCompleteModuleRegistrationCallback( CompleteModuleRegistrationCallbackFn_t pfnCallback, void* pArgument ) = 0;
virtual void RemoveCompleteModuleRegistrationCallback( CompleteModuleRegistrationCallbackFn_t pfnCallback, void* pArgument ) = 0;
virtual SchemaMetaInfoHandle_t<CSchemaType_Builtin> GetSchemaBuiltinType( SchemaBuiltinType_t eBuiltinType ) = 0;
virtual ~ISchemaSystem() = 0;
};
class CSchemaSystem : public ISchemaSystem
{
struct DetectedSchemaMismatch_t
{
CUtlString m_sBinding;
CUtlString m_sMismatch;
CUtlString m_sModule1;
CUtlString m_sModule2;
};
struct BindingsAddressRangeForModule_t
{
uintp m_minAddr;
uintp m_maxAddr;
};
struct CompleteModuleRegistrationCallback_t
{
CompleteModuleRegistrationCallbackFn_t m_pfnCallback;
void* m_pArgument;
};
public:
CUtlVector<ResourceManifestDesc_t*> m_ResourceManifestDescs;
int m_nNumConnections;
CThreadFastMutex m_Mutex;
#ifdef CONVAR_WORK_FINISHED
CConCommandMemberAccessor<CSchemaSystem> m_SchemaListBindings;
CConCommandMemberAccessor<CSchemaSystem> m_SchemaAllListBindings;
CConCommandMemberAccessor<CSchemaSystem> m_SchemaDumpBinding;
CConCommandMemberAccessor<CSchemaSystem> m_SchemaDetailedClassLayout;
CConCommandMemberAccessor<CSchemaSystem> m_SchemaStats;
CConCommandMemberAccessor<CSchemaSystem> m_SchemaMetaStats;
#else
#ifdef _WIN32
uint8 pad[288];
#else
uint8 pad[384];
#endif // _WIN32
#endif // CONVAR_WORK_FINISHED
CUtlVector<void*> m_LoadedModules;
CUtlVector<DetectedSchemaMismatch_t> m_DetectedSchemaMismatches;
bool m_bDefaultTypeScopeIsLocal;
bool m_bSchemaSystemIsReady;
CUtlStringMap<CSchemaSystemTypeScope*> m_TypeScopes;
CUtlStringMap<BindingsAddressRangeForModule_t> m_BindingsAddressRanges;
int m_nRegistrations;
int m_nIgnored;
int m_nRedundant;
size_t m_nIgnoredBytes;
CUtlVector<CompleteModuleRegistrationCallback_t> m_CompleteModuleRegistrationCallbacks;
};
#endif // SCHEMASYSTEM_H

View File

@ -0,0 +1,427 @@
#ifndef SCHEMATYPES_H
#define SCHEMATYPES_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/logging.h"
#include "tier0/threadtools.h"
#include "tier1/generichash.h"
#include "tier1/utlmap.h"
#include "tier1/utlstring.h"
class ISchemaSystemTypeScope;
class CSchemaSystemTypeScope;
class CSchemaClassInfo;
class CSchemaEnumInfo;
class CBufferString;
struct SchemaAtomicTypeInfo_t;
struct datamap_t;
enum SchemaClassFlags1_t
{
SCHEMA_CF1_HAS_VIRTUAL_MEMBERS = (1 << 0),
SCHEMA_CF1_IS_ABSTRACT = (1 << 1),
SCHEMA_CF1_HAS_TRIVIAL_CONSTRUCTOR = (1 << 2),
SCHEMA_CF1_HAS_TRIVIAL_DESTRUCTOR = (1 << 3),
SCHEMA_CF1_LIMITED_METADATA = (1 << 4),
SCHEMA_CF1_INHERITANCE_DEPTH_CALCULATED = (1 << 5),
SCHEMA_CF1_MODULE_LOCAL_TYPE_SCOPE = (1 << 6),
SCHEMA_CF1_GLOBAL_TYPE_SCOPE = (1 << 7),
SCHEMA_CF1_CONSTRUCT_ALLOWED = (1 << 8),
SCHEMA_CF1_CONSTRUCT_DISALLOWED = (1 << 9),
SCHEMA_CF1_INFO_TAG_MNetworkAssumeNotNetworkable = (1 << 10),
SCHEMA_CF1_INFO_TAG_MNetworkNoBase = (1 << 11),
SCHEMA_CF1_INFO_TAG_MIgnoreTypeScopeMetaChecks = (1 << 12),
SCHEMA_CF1_INFO_TAG_MDisableDataDescValidation = (1 << 13),
SCHEMA_CF1_INFO_TAG_MClassHasEntityLimitedDataDesc = (1 << 14),
SCHEMA_CF1_INFO_TAG_MClassHasCustomAlignedNewDelete = (1 << 15),
SCHEMA_CF1_UNK016 = (1 << 16),
SCHEMA_CF1_UNK017 = (1 << 17),
SCHEMA_CF1_INFO_TAG_MHasKV3TransferPolymorphicClassname = (1 << 18),
};
enum SchemaClassFlags2_t {};
enum SchemaEnumFlags_t
{
SCHEMA_EF_IS_REGISTERED = (1 << 0),
SCHEMA_EF_MODULE_LOCAL_TYPE_SCOPE = (1 << 1),
SCHEMA_EF_GLOBAL_TYPE_SCOPE = (1 << 2),
};
enum SchemaTypeCategory_t : uint8
{
SCHEMA_TYPE_BUILTIN = 0,
SCHEMA_TYPE_PTR,
SCHEMA_TYPE_BITFIELD,
SCHEMA_TYPE_FIXED_ARRAY,
SCHEMA_TYPE_ATOMIC,
SCHEMA_TYPE_DECLARED_CLASS,
SCHEMA_TYPE_DECLARED_ENUM,
SCHEMA_TYPE_NONE,
};
enum SchemaAtomicCategory_t : uint8
{
SCHEMA_ATOMIC_BASIC = 0,
SCHEMA_ATOMIC_T,
SCHEMA_ATOMIC_COLLECTION_OF_T,
SCHEMA_ATOMIC_TF,
SCHEMA_ATOMIC_TT,
SCHEMA_ATOMIC_TTF,
SCHEMA_ATOMIC_I,
SCHEMA_ATOMIC_NONE,
};
enum SchemaBuiltinType_t
{
SCHEMA_BUILTIN_INVALID = 0,
SCHEMA_BUILTIN_VOID,
SCHEMA_BUILTIN_CHAR,
SCHEMA_BUILTIN_INT8,
SCHEMA_BUILTIN_UINT8,
SCHEMA_BUILTIN_INT16,
SCHEMA_BUILTIN_UINT16,
SCHEMA_BUILTIN_INT32,
SCHEMA_BUILTIN_UINT32,
SCHEMA_BUILTIN_INT64,
SCHEMA_BUILTIN_UINT64,
SCHEMA_BUILTIN_FLOAT32,
SCHEMA_BUILTIN_FLOAT64,
SCHEMA_BUILTIN_BOOL,
SCHEMA_BUILTIN_COUNT,
};
enum SchemaClassManipulatorAction_t
{
SCHEMA_CLASS_MANIPULATOR_ACTION_REGISTER = 0,
SCHEMA_CLASS_MANIPULATOR_ACTION_REGISTER_PRE,
SCHEMA_CLASS_MANIPULATOR_ACTION_ALLOCATE,
SCHEMA_CLASS_MANIPULATOR_ACTION_DEALLOCATE,
SCHEMA_CLASS_MANIPULATOR_ACTION_CONSTRUCT_IN_PLACE,
SCHEMA_CLASS_MANIPULATOR_ACTION_DESCTRUCT_IN_PLACE,
SCHEMA_CLASS_MANIPULATOR_ACTION_GET_SCHEMA_BINDING,
};
enum SchemaAtomicManipulatorAction_t
{
SCHEMA_ATOMIC_MANIPULATOR_ACTION_GET_COUNT = 0,
SCHEMA_ATOMIC_MANIPULATOR_ACTION_GET_ELEMENT_CONST,
SCHEMA_ATOMIC_MANIPULATOR_ACTION_GET_ELEMENT,
SCHEMA_ATOMIC_MANIPULATOR_ACTION_SWAP_ELEMENTS,
SCHEMA_ATOMIC_MANIPULATOR_ACTION_INSERT_BEFORE,
SCHEMA_ATOMIC_MANIPULATOR_ACTION_REMOVE_MULTIPLE,
SCHEMA_ATOMIC_MANIPULATOR_ACTION_SET_COUNT,
};
typedef void* (*SchemaClassManipulatorFn_t)(SchemaClassManipulatorAction_t, void*, void*);
typedef void* (*SchemaAtomicManipulatorFn_t)(SchemaAtomicManipulatorAction_t, void*, void*, void*);
inline uint32 CSchemaType_Hash( const char *pString, int len )
{
return MurmurHash2( pString, len, 0xBAADFEED );
}
template <class T>
struct SchemaMetaInfoHandle_t
{
SchemaMetaInfoHandle_t() : m_pObj( NULL ) {}
SchemaMetaInfoHandle_t( T *obj ) : m_pObj( obj ) {}
T* Get() { return m_pObj; }
T* m_pObj;
};
template <class K, class V>
class CSchemaPtrMap
{
public:
CUtlMap<K, V> m_Map;
CThreadFastMutex m_Mutex;
};
class CSchemaType
{
public:
virtual bool IsValid() { return false; }
virtual const char* ToString( CBufferString& buff, bool bDontClearBuff ) { return ""; }
virtual void SpewDescription( LoggingChannelID_t channelID, const char* pszName ) {}
virtual bool GetSizeAndAlignment( int& nSize, uint8& nAlignment ) { return false; }
virtual bool CanReinterpretAs( const CSchemaType* pType ) { return false; }
virtual SchemaMetaInfoHandle_t<CSchemaType> GetInnerType() { return SchemaMetaInfoHandle_t<CSchemaType>(); }
virtual SchemaMetaInfoHandle_t<CSchemaType> GetInnermostType() { return SchemaMetaInfoHandle_t<CSchemaType>(); }
virtual bool IsA( const CSchemaType* pType ) { return false; }
virtual bool InternalMatchInnerAs( SchemaTypeCategory_t eTypeCategory, SchemaAtomicCategory_t eAtomicCategory ) { return false; }
virtual void unk001() {}
virtual void unk002() {}
virtual void unk003() {}
virtual void unk004() {}
virtual void unk005() {}
virtual void unk006() {}
virtual bool DependsOnlyOnUnresolvedOrGlobalTypes( ISchemaSystemTypeScope* pTypeScope ) { return false; }
virtual ~CSchemaType() = 0;
public:
CUtlString m_sTypeName;
CSchemaSystemTypeScope* m_pTypeScope;
SchemaTypeCategory_t m_eTypeCategory;
SchemaAtomicCategory_t m_eAtomicCategory;
};
class CSchemaType_Builtin : public CSchemaType
{
public:
SchemaBuiltinType_t m_eBuiltinType;
uint8 m_nSize;
};
class CSchemaType_Ptr : public CSchemaType
{
public:
CSchemaType* m_pObjectType;
};
class CSchemaType_Atomic : public CSchemaType
{
public:
SchemaAtomicTypeInfo_t* m_pAtomicInfo;
int m_nAtomicID;
uint16 m_nSize;
uint8 m_nAlignment;
};
class CSchemaType_Atomic_T : public CSchemaType_Atomic
{
public:
CSchemaType* m_pTemplateType;
};
class CSchemaType_Atomic_CollectionOfT : public CSchemaType_Atomic_T
{
public:
SchemaAtomicManipulatorFn_t m_pfnManipulator;
uint16 m_nElementSize;
};
class CSchemaType_Atomic_TF : public CSchemaType_Atomic_T
{
public:
int m_nFuncPtrSize;
};
class CSchemaType_Atomic_TT : public CSchemaType_Atomic_T
{
public:
CSchemaType* m_pTemplateType2;
};
class CSchemaType_Atomic_TTF : public CSchemaType_Atomic_TT
{
public:
int m_nFuncPtrSize;
};
class CSchemaType_Atomic_I : public CSchemaType_Atomic
{
public:
int m_nInteger;
};
class CSchemaType_DeclaredClass : public CSchemaType
{
public:
CSchemaClassInfo* m_pClassInfo;
bool m_bGlobalPromotionRequired;
};
class CSchemaType_DeclaredEnum : public CSchemaType
{
public:
CSchemaEnumInfo* m_pEnumInfo;
bool m_bGlobalPromotionRequired;
};
class CSchemaType_FixedArray : public CSchemaType
{
public:
int m_nElementCount;
uint16 m_nElementSize;
uint8 m_nElementAlignment;
CSchemaType* m_pElementType;
};
class CSchemaType_Bitfield : public CSchemaType
{
public:
int m_nSize;
};
struct SchemaMetadataEntryData_t
{
const char* m_pszName;
void* m_pData;
};
struct SchemaClassFieldData_t
{
const char* m_pszName;
CSchemaType* m_pType;
int m_nSingleInheritanceOffset;
int m_nStaticMetadataCount;
SchemaMetadataEntryData_t* m_pStaticMetadata;
};
struct SchemaStaticFieldData_t
{
const char* m_pszName;
CSchemaType* m_pType;
void* m_pInstance;
int m_nStaticMetadataCount;
SchemaMetadataEntryData_t* m_pStaticMetadata;
};
struct SchemaBaseClassInfoData_t
{
uint m_nOffset;
CSchemaClassInfo* m_pClass;
};
struct SchemaClassInfoData_t
{
CSchemaClassInfo* m_pSchemaBinding;
const char* m_pszName;
const char* m_pszProjectName;
int m_nSize;
uint16 m_nFieldCount;
uint16 m_nStaticFieldCount;
uint16 m_nStaticMetadataCount;
uint8 m_nAlignment;
uint8 m_nBaseClassCount;
uint16 m_nMultipleInheritanceDepth;
uint16 m_nSingleInheritanceDepth;
SchemaClassFieldData_t* m_pFields;
SchemaStaticFieldData_t* m_pStaticFields;
SchemaBaseClassInfoData_t* m_pBaseClasses;
datamap_t* m_pDataDescMap;
SchemaMetadataEntryData_t* m_pStaticMetadata;
CSchemaSystemTypeScope* m_pTypeScope;
CSchemaType_DeclaredClass* m_pDeclaredClass;
uint m_nFlags1;
uint m_nFlags2;
SchemaClassManipulatorFn_t m_pfnManipulator;
};
class CSchemaClassInfo : public SchemaClassInfoData_t
{
};
struct SchemaEnumeratorInfoData_t
{
const char* m_pszName;
int64 m_nValue;
int m_nStaticMetadataCount;
SchemaMetadataEntryData_t* m_pStaticMetadata;
};
struct SchemaEnumInfoData_t
{
CSchemaEnumInfo* m_pSchemaBinding;
const char* m_pszName;
const char* m_pszProjectName;
uint8 m_nSize;
uint8 m_nAlignment;
uint16 m_nFlags;
uint16 m_nEnumeratorCount;
uint16 m_nStaticMetadataCount;
SchemaEnumeratorInfoData_t* m_pEnumerators;
SchemaMetadataEntryData_t* m_pStaticMetadata;
CSchemaSystemTypeScope* m_pTypeScope;
int64 m_nMinEnumeratorValue;
int64 m_nMaxEnumeratorValue;
};
class CSchemaEnumInfo : public SchemaEnumInfoData_t
{
};
struct SchemaAtomicTypeInfo_t
{
const char* m_pszName1;
const char* m_pszName2;
int m_nAtomicID;
int m_nStaticMetadataCount;
SchemaMetadataEntryData_t* m_pStaticMetadata;
};
struct AtomicTypeInfo_T_t
{
int m_nAtomicID;
CSchemaType* m_pTemplateType;
SchemaAtomicManipulatorFn_t m_pfnManipulator;
};
struct AtomicTypeInfo_TF_t
{
int m_nAtomicID;
CSchemaType* m_pTemplateType;
int m_nFuncPtrSize;
};
struct AtomicTypeInfo_TT_t
{
int m_nAtomicID;
CSchemaType* m_pTemplateType;
CSchemaType* m_pTemplateType2;
};
struct AtomicTypeInfo_TTF_t
{
int m_nAtomicID;
CSchemaType* m_pTemplateType;
CSchemaType* m_pTemplateType2;
int m_nFuncPtrSize;
};
struct AtomicTypeInfo_I_t
{
int m_nAtomicID;
int m_nInteger;
};
struct TypeAndCountInfo_t
{
int m_nElementCount;
CSchemaType* m_pElementType;
};
#endif // SCHEMATYPES_H

View File

@ -85,7 +85,7 @@
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class CLoggingSystem; class CLoggingSystem;
class CThreadFastMutex; class CThreadSpinMutex;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Maximum length of a sprintf'ed logging message. // Maximum length of a sprintf'ed logging message.
@ -720,7 +720,7 @@ private:
// Protects all data in this class except the registered channels // Protects all data in this class except the registered channels
// (which are supposed to be registered using the macros at static/global init time). // (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. // 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 // 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. // for logging unless a given thread has pushed the logging state with bThreadLocal == true.

View File

@ -68,6 +68,13 @@
#define MEMALLOC_REGION_FREE_5 '=' #define MEMALLOC_REGION_FREE_5 '='
#define MEMALLOC_REGION_FREE_6 '?' #define MEMALLOC_REGION_FREE_6 '?'
enum MemAllocAttribute_t
{
MemAllocAttribute_Unk0 = 0,
MemAllocAttribute_Unk1 = 1,
MemAllocAttribute_Unk2 = 2
};
enum MemoryState enum MemoryState
{ {
MemoryState_UnexpectedlyAllocated = 0, MemoryState_UnexpectedlyAllocated = 0,
@ -236,7 +243,7 @@ public:
virtual int unk101() = 0; virtual int unk101() = 0;
// AMNOTE: Stub // 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 // AMNOTE: Copies data to an unknown struct of byte size 56
// Returns true if data was written, false otherwise // Returns true if data was written, false otherwise

View File

@ -14,6 +14,10 @@
#include "tier0/platform.h" #include "tier0/platform.h"
#include "tier0/dbg.h" #include "tier0/dbg.h"
#ifdef PLATFORM_WINDOWS_PC
#include <intrin.h>
#endif
#ifdef POSIX #ifdef POSIX
#include <pthread.h> #include <pthread.h>
#include <errno.h> #include <errno.h>
@ -38,10 +42,6 @@
#pragma warning(disable:4251) #pragma warning(disable:4251)
#endif #endif
#ifdef COMPILER_MSVC64
#include <intrin.h>
#endif
// #define THREAD_PROFILER 1 // #define THREAD_PROFILER 1
#define THREAD_MUTEX_TRACING_SUPPORTED #define THREAD_MUTEX_TRACING_SUPPORTED
@ -67,7 +67,11 @@ typedef void *HANDLE;
const unsigned TT_INFINITE = 0xffffffff; 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 void SetThreadedLoadLibraryFunc( ThreadedLoadLibraryFunc_t func );
PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc(); PLATFORM_INTERFACE ThreadedLoadLibraryFunc_t GetThreadedLoadLibraryFunc();
#if defined( _WIN32 ) #if defined( PLATFORM_WINDOWS_PC )
DLL_IMPORT unsigned long STDCALL GetCurrentThreadId(); DLL_IMPORT unsigned long STDCALL GetCurrentThreadId();
#define ThreadGetCurrentId GetCurrentThreadId #define ThreadGetCurrentId GetCurrentThreadId
#endif #endif
inline void ThreadPause() inline void ThreadPause()
{ {
#if defined( COMPILER_GCC ) #if defined( PLATFORM_WINDOWS_PC )
__asm __volatile( "pause" ); // Intrinsic for __asm pause; from <intrin.h>
#elif defined ( COMPILER_MSVC64 )
_mm_pause(); _mm_pause();
#elif defined( COMPILER_MSVC32 ) #elif defined( POSIX )
__asm pause; __asm __volatile( "pause" );
#elif defined( COMPILER_MSVCX360 ) #elif defined( _X360 )
YieldProcessor();
__asm { or r0,r0,r0 }
YieldProcessor();
__asm { or r1,r1,r1 }
#else #else
#error "implement me" #error "implement me"
#endif #endif
@ -142,77 +141,59 @@ PLATFORM_INTERFACE void ThreadSetAffinity( ThreadHandle_t hThread, int nAffinity
#define NOINLINE __attribute__ ((noinline)) #define NOINLINE __attribute__ ((noinline))
#endif #endif
#ifndef _X360 // ThreadMemoryBarrier is a fence/barrier sufficient for most uses. It prevents reads
#define ThreadMemoryBarrier() ((void)0) // 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 #else
#define ThreadMemoryBarrier() __lwsync() #error Every platform needs to define ThreadMemoryBarrier to at least prevent compiler reordering
#endif #endif
#if defined( _LINUX ) || defined( _OSX ) #if defined( POSIX )
#define USE_INTRINSIC_INTERLOCKED
// linux implementation // linux implementation
inline int32 ThreadInterlockedIncrement( int32 volatile *p ) 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 ); }
Assert( (size_t)p % 4 == 0 ); inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); return __sync_lock_test_and_set( p, value ); }
return __sync_fetch_and_add( p, 1 ) + 1; 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 ) 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 ); }
Assert( (size_t)p % 4 == 0 ); inline int64 ThreadInterlockedExchange64( int64 volatile *p, int64 value ) { Assert( (size_t)p % 8 == 0 ); return __sync_lock_test_and_set( p, value ); }
return __sync_fetch_and_add( p, -1 ) - 1; 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 ) 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 ); }
Assert( (size_t)p % 4 == 0 ); 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 ); }
int32 nRet; #elif ( defined( PLATFORM_WINDOWS_PC ) && ( _MSC_VER >= 1310 ) )
// windows implemnetation using compiler intrinsics
// Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it. #pragma intrinsic( _InterlockedIncrement )
__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 )
#pragma intrinsic( _InterlockedDecrement ) #pragma intrinsic( _InterlockedDecrement )
#pragma intrinsic( _InterlockedExchange ) #pragma intrinsic( _InterlockedExchange )
#pragma intrinsic( _InterlockedExchangeAdd ) #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 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 ); } 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 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 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 ); } 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 #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 ThreadInterlockedIncrement( int32 volatile * ) NOINLINE;
PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE; PLATFORM_INTERFACE int32 ThreadInterlockedDecrement( int32 volatile * ) NOINLINE;
PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE; PLATFORM_INTERFACE int32 ThreadInterlockedExchange( int32 volatile *, int32 value ) NOINLINE;
PLATFORM_INTERFACE int32 ThreadInterlockedExchangeAdd( 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 int32 ThreadInterlockedCompareExchange( int32 volatile *, int32 value, int32 comperand ) NOINLINE;
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE; PLATFORM_INTERFACE bool ThreadInterlockedAssignIf( int32 volatile *, int32 value, int32 comperand ) NOINLINE;
#endif
PLATFORM_INTERFACE int64 ThreadInterlockedIncrement64( int64 volatile * ) NOINLINE;
PLATFORM_INTERFACE int64 ThreadInterlockedDecrement64( int64 volatile * ) NOINLINE;
PLATFORM_INTERFACE int64 ThreadInterlockedExchange64( int64 volatile *, int64 value ) NOINLINE;
PLATFORM_INTERFACE int64 ThreadInterlockedExchangeAdd64( int64 volatile *, int64 value ) NOINLINE;
PLATFORM_INTERFACE int64 ThreadInterlockedCompareExchange64( int64 volatile *, int64 value, int64 comperand ) NOINLINE;
PLATFORM_INTERFACE bool ThreadInterlockedAssignIf64(volatile int64 *pDest, int64 value, int64 comperand ) NOINLINE;
#if defined( USE_INTRINSIC_INTERLOCKED ) && !defined( PLATFORM_64BITS )
#define TIPTR()
inline void *ThreadInterlockedExchangePointer( void * volatile *p, void *value ) { return (void *)( ( intp )ThreadInterlockedExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value) ) ); }
inline void *ThreadInterlockedCompareExchangePointer( void * volatile *p, void *value, void *comperand ) { return (void *)( ( intp )ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) ); }
inline bool ThreadInterlockedAssignPointerIf( void * volatile *p, void *value, void *comperand ) { return ( ThreadInterlockedCompareExchange( reinterpret_cast<intp volatile *>(p), reinterpret_cast<intp>(value), reinterpret_cast<intp>(comperand) ) == reinterpret_cast<intp>(comperand) ); }
#else
PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE; PLATFORM_INTERFACE void *ThreadInterlockedExchangePointer( void * volatile *, void *value ) NOINLINE;
PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE; PLATFORM_INTERFACE void *ThreadInterlockedCompareExchangePointer( void * volatile *, void *value, void *comperand ) NOINLINE;
PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE; PLATFORM_INTERFACE bool ThreadInterlockedAssignPointerIf( void * volatile *, void *value, void *comperand ) NOINLINE;
#endif #endif
inline unsigned ThreadInterlockedExchangeSubtract( int32 volatile *p, int32 value ) { return ThreadInterlockedExchangeAdd( (int32 volatile *)p, -value ); } 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 *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 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 ) ); } 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 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 ThreadInterlockedIncrement( uint32 volatile *p ) { return ThreadInterlockedIncrement( (int32 volatile *)p ); }
inline unsigned ThreadInterlockedDecrement( uint32 volatile *p ) { return ThreadInterlockedDecrement( (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 ); } //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 // Access to VTune thread profiling
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -544,7 +572,17 @@ template <typename T>
class CInterlockedPtr class CInterlockedPtr
{ {
public: 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 ) {} CInterlockedPtr( T *value ) : m_value( value ) {}
operator T *() const { return m_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 ); }
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++() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, sizeof(T) )) + 1; }
T *operator++(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, sizeof(T) ); } T *operator++(int) { return (T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, sizeof(T) ); }
T *operator--() { return ((T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) )) - 1; } T *operator--() { return ((T *)THREADINTERLOCKEDEXCHANGEADD( &m_value, -sizeof(T) )) - 1; }
T *operator--(int) { return (T *)ThreadInterlockedExchangeAdd( (int32 *)&m_value, -sizeof(T) ); } 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 ); } 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; } 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 ); } void operator-=( int subtract ) { operator+=( -subtract ); }
// Atomic add is like += except it returns the previous value as its return value // 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; }
T *operator-( int rhs ) const { return m_value - rhs; } T *operator-( int rhs ) const { return m_value - rhs; }
@ -578,6 +616,8 @@ public:
private: private:
T * volatile m_value; T * volatile m_value;
#undef THREADINTERLOCKEDEXCHANGEADD
}; };
@ -591,22 +631,22 @@ private:
class PLATFORM_CLASS CThreadMutex class PLATFORM_CLASS CThreadMutex
{ {
public: public:
CThreadMutex( const char* pDebugName ); CThreadMutex( const char* pDebugName = NULL );
~CThreadMutex(); ~CThreadMutex();
//------------------------------------------------------ //------------------------------------------------------
// Mutex acquisition/release. Const intentionally defeated. // Mutex acquisition/release. Const intentionally defeated.
//------------------------------------------------------ //------------------------------------------------------
void Lock( const char *pFileName, int nLine ); void Lock( const char *pFileName = NULL, int nLine = -1 );
void Lock( const char *pFileName, int nLine ) const { (const_cast<CThreadMutex *>(this))->Lock( pFileName, nLine ); } void Lock( const char *pFileName = NULL, int nLine = -1 ) const { (const_cast<CThreadMutex *>(this))->Lock( pFileName, nLine ); }
void Unlock( const char *pFileName, int nLine ); void Unlock( const char *pFileName = NULL, int nLine = -1 );
void Unlock( const char *pFileName, int nLine ) const { (const_cast<CThreadMutex *>(this))->Unlock( pFileName, nLine ); } void Unlock( const char *pFileName = NULL, int nLine = -1 ) const { (const_cast<CThreadMutex *>(this))->Unlock( pFileName, nLine ); }
bool TryLock( const char *pFileName, int nLine ); bool TryLock( const char *pFileName = NULL, int nLine = -1 );
bool TryLock( const char *pFileName, int nLine ) const { return (const_cast<CThreadMutex *>(this))->TryLock( pFileName, nLine ); } bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const { return (const_cast<CThreadMutex *>(this))->TryLock( pFileName, nLine ); }
void LockSilent( const char *pFileName, int nLine ); // A Lock() operation which never spews. Required by the logging system to prevent badness. void 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, int nLine ); // An Unlock() 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 // Use this to make deadlocks easier to track by asserting
@ -642,14 +682,11 @@ private:
#else #else
#error #error
#endif #endif
#ifdef THREAD_MUTEX_TRACING_SUPPORTED
// Debugging (always herge to allow mixed debug/release builds w/o changing size) // Debugging (always herge to allow mixed debug/release builds w/o changing size)
ThreadId_t m_currentOwnerID; ThreadId_t m_currentOwnerID;
uint16 m_lockCount; uint16 m_lockCount;
bool m_bTrace; bool m_bTrace;
const char* m_pDebugName; const char* m_pDebugName;
#endif
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -664,19 +701,25 @@ private:
#if !defined(THREAD_PROFILER) #if !defined(THREAD_PROFILER)
class CThreadFastMutex class CThreadSpinMutex
{ {
public: public:
CThreadFastMutex() CThreadSpinMutex( const char* pDebugName = NULL )
: m_ownerID( 0 ), : m_ownerID( 0 ),
m_depth( 0 ) m_depth( 0 ),
m_pDebugName( NULL/*pDebugName*/ )
{ {
} }
private: 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; return false;
ThreadMemoryBarrier(); ThreadMemoryBarrier();
@ -684,15 +727,15 @@ private:
return true; 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: public:
bool TryLock() volatile bool TryLock( const char *pFileName = NULL, int nLine = -1 ) volatile
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_depth == INT_MAX ) if ( m_depth == INT_MAX )
@ -701,20 +744,20 @@ public:
if ( m_depth < 0 ) if ( m_depth < 0 )
DebuggerBreak(); DebuggerBreak();
#endif #endif
return TryLockInline( ThreadGetCurrentId() ); return TryLockInline( pFileName, nLine, ThreadGetCurrentId() );
} }
#ifndef _DEBUG #ifndef _DEBUG
FORCEINLINE FORCEINLINE
#endif #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(); ThreadPause();
Lock( threadId, nSpinSleepTime ); Lock( pFileName, nLine, threadId, nSpinSleepTime );
} }
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ownerID != ThreadGetCurrentId() ) if ( m_ownerID != ThreadGetCurrentId() )
@ -731,7 +774,7 @@ public:
#ifndef _DEBUG #ifndef _DEBUG
FORCEINLINE FORCEINLINE
#endif #endif
void Unlock() volatile void Unlock( const char *pFileName = NULL, int nLine = -1 ) volatile
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ownerID != ThreadGetCurrentId() ) if ( m_ownerID != ThreadGetCurrentId() )
@ -745,41 +788,48 @@ public:
if ( !m_depth ) if ( !m_depth )
{ {
ThreadMemoryBarrier(); ThreadMemoryBarrier();
ThreadInterlockedExchange( &m_ownerID, 0 ); #ifdef _WIN32
ThreadInterlockedExchange( (volatile int32 *)&m_ownerID, 0 );
#else
ThreadInterlockedExchange64( (volatile int64 *)&m_ownerID, 0 );
#endif
} }
} }
bool TryLock() const volatile { return (const_cast<CThreadFastMutex *>(this))->TryLock(); } bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const volatile { return (const_cast<CThreadSpinMutex *>(this))->TryLock( pFileName, nLine ); }
void Lock(unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadFastMutex *>(this))->Lock( nSpinSleepTime ); } void Lock( const char *pFileName = NULL, int nLine = -1, unsigned nSpinSleepTime = 0 ) const volatile { (const_cast<CThreadSpinMutex *>(this))->Lock( pFileName, nLine, nSpinSleepTime ); }
void Unlock() const volatile { (const_cast<CThreadFastMutex *>(this))->Unlock(); } void Unlock( const char *pFileName = NULL, int nLine = -1 ) const volatile { (const_cast<CThreadSpinMutex *>(this))->Unlock( pFileName, nLine ); }
// To match regular CThreadMutex: // To match regular CThreadMutex:
bool AssertOwnedByCurrentThread() { return true; } bool AssertOwnedByCurrentThread() { return true; }
void SetTrace( bool ) {} void SetTrace( bool ) {}
uint32 GetOwnerId() const { return m_ownerID; } ThreadId_t GetOwnerId() const { return m_ownerID; }
int GetDepth() const { return m_depth; } int GetDepth() const { return m_depth; }
private: private:
volatile uint32 m_ownerID; volatile ThreadId_t m_ownerID;
int m_depth; int m_depth;
const char* m_pDebugName;
}; };
class ALIGN128 CAlignedThreadFastMutex : public CThreadFastMutex class ALIGN128 CAlignedThreadFastMutex : public CThreadSpinMutex
{ {
public: public:
CAlignedThreadFastMutex() CAlignedThreadFastMutex( const char* pDebugName = NULL ) : CThreadSpinMutex( pDebugName )
{ {
Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 ); Assert( (size_t)this % 128 == 0 && sizeof(*this) == 128 );
} }
private: private:
uint8 pad[128-sizeof(CThreadFastMutex)]; uint8 pad[128-sizeof(CThreadSpinMutex)];
}; } ALIGN128_POST;
#else #else
typedef CThreadMutex CThreadFastMutex; typedef CThreadMutex CThreadSpinMutex;
#endif #endif
typedef CThreadSpinMutex CThreadFastMutex;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -787,16 +837,16 @@ typedef CThreadMutex CThreadFastMutex;
class CThreadNullMutex class CThreadNullMutex
{ {
public: public:
CThreadNullMutex( const char* pDebugName ) {} CThreadNullMutex( const char* pDebugName = NULL ) {}
static void Lock( const char *pFileName, int nLine ) {} static void Lock( const char *pFileName = NULL, int nLine = -1 ) {}
static void Unlock( const char *pFileName, int nLine ) {} static void Unlock( const char *pFileName = NULL, int nLine = -1 ) {}
static bool TryLock( const char *pFileName, int nLine ) { return true; } static bool TryLock( const char *pFileName = NULL, int nLine = -1 ) { return true; }
static bool AssertOwnedByCurrentThread() { return true; } static bool AssertOwnedByCurrentThread() { return true; }
static void SetTrace( bool b ) {} static void SetTrace( bool b ) {}
static uint32 GetOwnerId() { return 0; } static ThreadId_t GetOwnerId() { return 0; }
static int GetDepth() { return 0; } static int GetDepth() { return 0; }
}; };
@ -811,13 +861,15 @@ template <class BaseClass, bool *pCondition>
class CThreadConditionalMutex : public BaseClass class CThreadConditionalMutex : public BaseClass
{ {
public: public:
void Lock() { if ( *pCondition ) BaseClass::Lock(); } CThreadConditionalMutex( const char* pDebugName = NULL ) : BaseClass( pDebugName ) {}
void Lock() const { if ( *pCondition ) BaseClass::Lock(); }
void Unlock() { if ( *pCondition ) BaseClass::Unlock(); }
void Unlock() const { if ( *pCondition ) BaseClass::Unlock(); }
bool TryLock() { if ( *pCondition ) return BaseClass::TryLock(); else return true; } void Lock( const char *pFileName = NULL, int nLine = -1 ) { if ( *pCondition ) BaseClass::Lock( pFileName, nLine ); }
bool TryLock() const { if ( *pCondition ) return BaseClass::TryLock(); else return true; } 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; } bool AssertOwnedByCurrentThread() { if ( *pCondition ) return BaseClass::AssertOwnedByCurrentThread(); else return true; }
void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); } void SetTrace( bool b ) { if ( *pCondition ) BaseClass::SetTrace( b ); }
}; };
@ -830,10 +882,12 @@ template <class BaseClass>
class CThreadTerminalMutex : public BaseClass class CThreadTerminalMutex : public BaseClass
{ {
public: public:
bool TryLock() { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; } CThreadTerminalMutex( const char* pDebugName = NULL ) : BaseClass( pDebugName ) {}
bool TryLock() const { if ( !BaseClass::TryLock() ) { DebuggerBreak(); return false; } return true; }
void Lock() { if ( !TryLock() ) BaseClass::Lock(); } bool TryLock( const char *pFileName = NULL, int nLine = -1 ) { if ( !BaseClass::TryLock( pFileName, nLine ) ) { DebuggerBreak(); return false; } return true; }
void Lock() const { if ( !TryLock() ) BaseClass::Lock(); } bool TryLock( const char *pFileName = NULL, int nLine = -1 ) const { if ( !BaseClass::TryLock( pFileName, nLine ) ) { DebuggerBreak(); return false; } return true; }
void Lock( const char *pFileName = NULL, int nLine = -1 ) { if ( !TryLock( pFileName, nLine ) ) BaseClass::Lock( pFileName, nLine ); }
void Lock( const char *pFileName = NULL, int nLine = -1 ) const { if ( !TryLock( pFileName, nLine ) ) BaseClass::Lock( pFileName, nLine ); }
}; };
@ -848,16 +902,16 @@ template <class MUTEX_TYPE = CThreadMutex>
class CAutoLockT class CAutoLockT
{ {
public: 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(); m_lock.Lock( pFileName, nLine );
} }
FORCEINLINE CAutoLockT(const MUTEX_TYPE &lock) FORCEINLINE CAutoLockT( const MUTEX_TYPE &lock, const char *pFileName, int nLine )
: m_lock(const_cast<MUTEX_TYPE &>(lock)) : m_lock(const_cast<MUTEX_TYPE &>(lock))
{ {
m_lock.Lock(); m_lock.Lock( pFileName, nLine );
} }
FORCEINLINE ~CAutoLockT() FORCEINLINE ~CAutoLockT()
@ -870,33 +924,24 @@ private:
MUTEX_TYPE &m_lock; MUTEX_TYPE &m_lock;
// Disallow copying // Disallow copying
CAutoLockT( const CAutoLockT<MUTEX_TYPE> & ); CAutoLockT<MUTEX_TYPE>( const CAutoLockT<MUTEX_TYPE> & );
CAutoLockT &operator=( const CAutoLockT<MUTEX_TYPE> & ); CAutoLockT<MUTEX_TYPE> &operator=( const CAutoLockT<MUTEX_TYPE> & );
}; };
typedef CAutoLockT<CThreadMutex> CAutoLock; typedef CAutoLockT<CThreadMutex> CAutoLock;
//--------------------------------------------------------- //---------------------------------------------------------
template <int size> struct CAutoLockTypeDeducer {};
template <> struct CAutoLockTypeDeducer<sizeof(CThreadMutex)> { typedef CThreadMutex Type_t; };
template <> struct CAutoLockTypeDeducer<sizeof(CThreadNullMutex)> { typedef CThreadNullMutex Type_t; };
#if !defined(THREAD_PROFILER)
template <> struct CAutoLockTypeDeducer<sizeof(CThreadFastMutex)> { typedef CThreadFastMutex Type_t; };
template <> struct CAutoLockTypeDeducer<sizeof(CAlignedThreadFastMutex)> { typedef CAlignedThreadFastMutex Type_t; };
#endif
#define AUTO_LOCK_( type, mutex ) \ #define AUTO_LOCK_( type, mutex ) \
CAutoLockT< type > UNIQUE_ID( static_cast<const type &>( mutex ) ) CAutoLockT< type > UNIQUE_ID( static_cast<const type &>( mutex ), __FILE__, __LINE__ )
#ifdef COMPILER_GCC template<typename T> T strip_cv_quals_for_mutex(T&);
#define AUTO_LOCK( mutex ) \ template<typename T> T strip_cv_quals_for_mutex(const T&);
AUTO_LOCK_( typename CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex ) template<typename T> T strip_cv_quals_for_mutex(volatile T&);
#else template<typename T> T strip_cv_quals_for_mutex(const volatile T&);
#define AUTO_LOCK( mutex ) \
AUTO_LOCK_( CAutoLockTypeDeducer<sizeof(mutex)>::Type_t, mutex )
#endif
#define AUTO_LOCK( mutex ) \
AUTO_LOCK_( decltype(::strip_cv_quals_for_mutex(mutex)), mutex )
#define AUTO_LOCK_FM( mutex ) \ #define AUTO_LOCK_FM( mutex ) \
AUTO_LOCK_( CThreadFastMutex, 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: 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(); //m_pDebugName = pDebugName;
bool TryLockForRead(); }
void LockForRead(); bool TryLockForWrite( const char *pFileName = NULL, int nLine = -1 );
void UnlockRead(); bool TryLockForRead( const char *pFileName = NULL, int nLine = -1 );
void LockForWrite();
void UnlockWrite();
bool TryLockForWrite() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite(); } PLATFORM_CLASS void LockForRead( const char *pFileName = NULL, int nLine = -1 );
bool TryLockForRead() const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead(); } PLATFORM_CLASS void UnlockRead( const char *pFileName = NULL, int nLine = -1 );
void LockForRead() const { const_cast<CThreadSpinRWLock *>(this)->LockForRead(); } void LockForWrite( const char *pFileName = NULL, int nLine = -1 );
void UnlockRead() const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead(); } PLATFORM_CLASS void UnlockWrite( const char *pFileName = NULL, int nLine = -1 );
void LockForWrite() const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite(); }
void UnlockWrite() const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite(); } bool TryLockForWrite( const char *pFileName = NULL, int nLine = -1 ) const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForWrite( pFileName, nLine ); }
bool TryLockForRead( const char *pFileName = NULL, int nLine = -1 ) const { return const_cast<CThreadSpinRWLock *>(this)->TryLockForRead( pFileName, nLine ); }
void LockForRead( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->LockForRead( pFileName, nLine ); }
void UnlockRead( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->UnlockRead( pFileName, nLine ); }
void LockForWrite( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->LockForWrite( pFileName, nLine ); }
void UnlockWrite( const char *pFileName = NULL, int nLine = -1 ) const { const_cast<CThreadSpinRWLock *>(this)->UnlockWrite( pFileName, nLine ); }
private: private:
// This structure is used as an atomic & exchangeable 64-bit value. It would probably be better to just have one 64-bit value struct LockInfo_t
// 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 ThreadId_t m_writerId;
{ #ifdef _WIN32
uint32 m_writerId; int32 m_nReaders;
int m_nReaders; #else
}; int64 m_nReaders;
int64 m_i64; #endif
}; };
bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand ); bool AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand );
bool TryLockForWrite( const uint32 threadId ); bool TryLockForWrite( const char *pFileName, int nLine, const ThreadId_t threadId );
void SpinLockForWrite( const uint32 threadId ); PLATFORM_CLASS void SpinLockForWrite( const char *pFileName, int nLine, const ThreadId_t threadId );
volatile LockInfo_t m_lockInfo; volatile LockInfo_t m_lockInfo;
CInterlockedInt m_nWriters; CInterlockedInt m_nWriters;
const char* m_pDebugName;
#ifdef _WIN32
} ALIGN8_POST; } ALIGN8_POST;
#else
} ALIGN16_POST;
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// //
@ -1494,7 +1556,7 @@ inline void CThreadMutex::Lock( const char *pFileName, int nLine )
ThreadId_t thisThreadID = ThreadGetCurrentId(); ThreadId_t thisThreadID = ThreadGetCurrentId();
#ifdef THREAD_MUTEX_TRACING_ENABLED #ifdef THREAD_MUTEX_TRACING_ENABLED
if ( m_bTrace && m_currentOwnerID && ( m_currentOwnerID != thisThreadID ) ) 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 #endif
LockSilent( pFileName, nLine ); LockSilent( pFileName, nLine );
@ -1505,7 +1567,7 @@ inline void CThreadMutex::Lock( const char *pFileName, int nLine )
m_currentOwnerID = thisThreadID; m_currentOwnerID = thisThreadID;
#ifdef THREAD_MUTEX_TRACING_ENABLED #ifdef THREAD_MUTEX_TRACING_ENABLED
if ( m_bTrace ) 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 #endif
} }
m_lockCount++; m_lockCount++;
@ -1523,7 +1585,7 @@ inline void CThreadMutex::Unlock( const char *pFileName, int nLine )
{ {
#ifdef THREAD_MUTEX_TRACING_ENABLED #ifdef THREAD_MUTEX_TRACING_ENABLED
if ( m_bTrace ) 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 #endif
m_currentOwnerID = 0; m_currentOwnerID = 0;
} }
@ -1551,7 +1613,7 @@ inline bool CThreadMutex::AssertOwnedByCurrentThread()
if (ThreadGetCurrentId() == m_currentOwnerID) if (ThreadGetCurrentId() == m_currentOwnerID)
return true; return true;
#ifdef THREAD_MUTEX_TRACING_ENABLED #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 #endif
return false; return false;
} }
@ -1570,7 +1632,7 @@ inline void CThreadMutex::SetTrace( bool bTrace )
#elif defined(POSIX) #elif defined(POSIX)
inline CThreadMutex::CThreadMutex( const char* pDebugName ) : 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 // enable recursive locks as we need them
pthread_mutexattr_init( &m_Attr ); pthread_mutexattr_init( &m_Attr );
@ -1652,24 +1714,24 @@ inline CThreadRWLock::CThreadRWLock()
inline void CThreadRWLock::LockForRead() inline void CThreadRWLock::LockForRead()
{ {
m_mutex.Lock(); m_mutex.Lock( __FILE__, __LINE__ );
if ( m_nWriters) if ( m_nWriters)
{ {
WaitForRead(); WaitForRead();
} }
m_nActiveReaders++; m_nActiveReaders++;
m_mutex.Unlock(); m_mutex.Unlock( __FILE__, __LINE__ );
} }
inline void CThreadRWLock::UnlockRead() inline void CThreadRWLock::UnlockRead()
{ {
m_mutex.Lock(); m_mutex.Lock( __FILE__, __LINE__ );
m_nActiveReaders--; m_nActiveReaders--;
if ( m_nActiveReaders == 0 && m_nWriters != 0 ) if ( m_nActiveReaders == 0 && m_nWriters != 0 )
{ {
m_CanWrite.Set(); 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 ) inline bool CThreadSpinRWLock::AssignIf( const LockInfo_t &newValue, const LockInfo_t &comperand )
{ {
// Note: using unions guarantees no aliasing bugs. Casting structures through *(int64*)& #ifdef _WIN32
// may create hard-to-catch bugs because when you do that, compiler doesn't know that the newly computed pointer return ThreadInterlockedAssignIf64( (volatile int64 *)&m_lockInfo, *((int64 *)&newValue), *((int64 *)&comperand) );
// 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. #else
return ThreadInterlockedAssignIf64( &m_lockInfo.m_i64, newValue.m_i64, comperand.m_i64 ); 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 // 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 ) ) 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; return false;
} }
static const LockInfo_t oldValue = {{ 0, 0 }}; static const LockInfo_t oldValue = { 0, 0 };
LockInfo_t newValue = {{ threadId, 0 }}; LockInfo_t newValue = { threadId, 0 };
if ( AssignIf( newValue, oldValue ) ) if ( AssignIf( newValue, oldValue ) )
{ {
ThreadMemoryBarrier(); ThreadMemoryBarrier();
@ -1705,10 +1768,10 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForWrite( const uint32 threadId )
return false; return false;
} }
inline bool CThreadSpinRWLock::TryLockForWrite() inline bool CThreadSpinRWLock::TryLockForWrite( const char *pFileName, int nLine )
{ {
m_nWriters++; m_nWriters++;
if ( !TryLockForWrite( ThreadGetCurrentId() ) ) if ( !TryLockForWrite( pFileName, nLine, ThreadGetCurrentId() ) )
{ {
m_nWriters--; m_nWriters--;
return false; return false;
@ -1716,7 +1779,7 @@ inline bool CThreadSpinRWLock::TryLockForWrite()
return true; return true;
} }
FORCEINLINE bool CThreadSpinRWLock::TryLockForRead() FORCEINLINE bool CThreadSpinRWLock::TryLockForRead( const char *pFileName, int nLine )
{ {
if ( m_nWriters != 0 ) if ( m_nWriters != 0 )
{ {
@ -1726,21 +1789,10 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
LockInfo_t oldValue; LockInfo_t oldValue;
LockInfo_t newValue; 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_nReaders = m_lockInfo.m_nReaders;
oldValue.m_writerId = 0; oldValue.m_writerId = 0;
newValue.m_nReaders = oldValue.m_nReaders + 1; newValue.m_nReaders = oldValue.m_nReaders + 1;
newValue.m_writerId = 0; newValue.m_writerId = 0;
}
if ( AssignIf( newValue, oldValue ) ) if ( AssignIf( newValue, oldValue ) )
{ {
@ -1750,16 +1802,16 @@ FORCEINLINE bool CThreadSpinRWLock::TryLockForRead()
return false; 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++; m_nWriters++;
if ( !TryLockForWrite( threadId ) ) if ( !TryLockForWrite( pFileName, nLine, threadId ) )
{ {
ThreadPause(); ThreadPause();
SpinLockForWrite( threadId ); SpinLockForWrite( pFileName, nLine, threadId );
} }
} }

View File

@ -16,7 +16,9 @@ template <class T>
class CUtlStringMap class CUtlStringMap
{ {
public: 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 )
{ {
} }

View File

@ -34,13 +34,13 @@ public:
DLL_CLASS_IMPORT void Purge( void ); DLL_CLASS_IMPORT void Purge( void );
DLL_CLASS_IMPORT MemBlockHandle_t Alloc( unsigned int nSize ); DLL_CLASS_IMPORT MemBlockHandle_t Alloc( unsigned int nSize );
DLL_CLASS_IMPORT MemBlockHandle_t AllocAndCopy( const char* pBuf, 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 void SetPageSize( unsigned int nPageSize );
DLL_CLASS_IMPORT MemBlockHandle_t FindPageWithSpace( unsigned int nSpace );
void* GetBlock( MemBlockHandle_t handle ) const; void* GetBlock( MemBlockHandle_t handle ) const;
private: private:
DLL_CLASS_IMPORT int FindPageWithSpace( unsigned int nSpace ) const;
struct MemPage_t struct MemPage_t
{ {

View File

@ -28,34 +28,30 @@
// Purpose: Optimized pool memory allocator // 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: public:
// Ways the memory pool can grow when it needs to make a new blob. 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 );
enum MemoryPoolGrowType_t DLL_CLASS_IMPORT ~CUtlMemoryPoolBase();
{
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.
};
CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); // Resets the pool
~CUtlMemoryPool(); 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. DLL_CLASS_IMPORT void* Alloc(); // Allocate the element size you specified in the constructor.
void* Alloc( size_t amount ); DLL_CLASS_IMPORT void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction
void* AllocZero(); // Allocate the element size you specified in the constructor, zero the memory before construction DLL_CLASS_IMPORT void Free( void *pMem );
void* AllocZero( size_t amount );
void Free(void *pMem);
// Frees everything // Frees everything
void Clear(); DLL_CLASS_IMPORT void Clear();
// Error reporting...
static void SetErrorReportFunc( MemoryPoolReportFunc_t func );
// returns number of allocated blocks // returns number of allocated blocks
int Count() const { return m_BlocksAllocated; } int Count() const { return m_BlocksAllocated; }
@ -63,62 +59,47 @@ public:
int BlockSize() const { return m_BlockSize; } int BlockSize() const { return m_BlockSize; }
int Size() const { return m_NumBlobs * m_BlocksPerBlob * 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: protected:
struct FreeList_t
{
FreeList_t *m_pNext;
};
class CBlob class CBlob
{ {
public: public:
CBlob *m_pPrev, *m_pNext; CBlob *m_pNext;
int m_NumBytes; // Number of bytes in this blob. int m_NumBytes; // Number of bytes in this blob.
char m_Data[1]; char m_Data[1];
char m_Padding[3]; // to int align the struct char m_Padding[3]; // to int align the struct
}; };
// Resets the pool DLL_CLASS_IMPORT FreeList_t* AddNewBlob();
void Init(); DLL_CLASS_IMPORT void ResetAllocationCounts();
void AddNewBlob(); DLL_CLASS_IMPORT void InternalClear( CBlob *blob, FreeList_t *free_list );
void ReportLeaks(); DLL_CLASS_IMPORT void ClearDestruct( void (*)( void* ) );
int m_BlockSize; int m_BlockSize;
int m_BlocksPerBlob; int m_BlocksPerBlob;
int m_GrowMode; // GROW_ enum. MemoryPoolGrowType_t m_GrowMode;
int m_BlocksAllocated; CInterlockedInt m_BlocksAllocated;
int m_PeakAlloc; CInterlockedInt m_PeakAlloc;
unsigned short m_nAlignment; unsigned short m_nAlignment;
unsigned short m_NumBlobs; unsigned short m_NumBlobs;
// FIXME: Change m_ppMemBlob into a growable array? FreeList_t** m_ppTailOfFreeList;
void *m_pHeadOfFreeList; FreeList_t* 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;
static MemoryPoolReportFunc_t g_ReportFunc; CBlob** m_ppBlobTail;
}; CBlob* m_pBlobHead;
MemAllocAttribute_t m_AllocAttribute;
//----------------------------------------------------------------------------- bool m_Unk1;
// 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)
}; };
@ -127,19 +108,26 @@ private:
// and construction and destruction of objects. // and construction and destruction of objects.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template< class T > template< class T >
class CClassMemoryPool : public CUtlMemoryPool class CUtlMemoryPool : public CUtlMemoryPoolBase
{ {
public: public:
CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : CUtlMemoryPool( int numElements, MemoryPoolGrowType_t growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = MEM_ALLOC_CLASSNAME(T), MemAllocAttribute_t allocAttribute = MemAllocAttribute_Unk0 )
CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {} : CUtlMemoryPoolBase( sizeof(T), numElements, alignof(T), growMode, pszAllocOwner, allocAttribute ) {}
T* Alloc(); T* Alloc();
T* AllocZero(); T* AllocZero();
void Free( T *pMem ); void Free( T *pMem );
void Clear(); void Clear();
}; };
//-----------------------------------------------------------------------------
// Multi-thread/Thread Safe Memory Class
//-----------------------------------------------------------------------------
template< class T >
using CUtlMemoryPoolMT = CUtlMemoryPool<T>;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Specialized pool for aligned data management (e.g., Xbox textures) // Specialized pool for aligned data management (e.g., Xbox textures)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -317,13 +305,13 @@ public:
template< class T > template< class T >
inline T* CClassMemoryPool<T>::Alloc() inline T* CUtlMemoryPool<T>::Alloc()
{ {
T *pRet; T *pRet;
{ {
MEM_ALLOC_CREDIT_CLASS(); MEM_ALLOC_CREDIT_CLASS();
pRet = (T*)CUtlMemoryPool::Alloc(); pRet = (T*)CUtlMemoryPoolBase::Alloc();
} }
if ( pRet ) if ( pRet )
@ -334,13 +322,13 @@ inline T* CClassMemoryPool<T>::Alloc()
} }
template< class T > template< class T >
inline T* CClassMemoryPool<T>::AllocZero() inline T* CUtlMemoryPool<T>::AllocZero()
{ {
T *pRet; T *pRet;
{ {
MEM_ALLOC_CREDIT_CLASS(); MEM_ALLOC_CREDIT_CLASS();
pRet = (T*)CUtlMemoryPool::AllocZero(); pRet = (T*)CUtlMemoryPoolBase::AllocZero();
} }
if ( pRet ) if ( pRet )
@ -351,44 +339,20 @@ inline T* CClassMemoryPool<T>::AllocZero()
} }
template< class T > template< class T >
inline void CClassMemoryPool<T>::Free(T *pMem) inline void CUtlMemoryPool<T>::Free(T *pMem)
{ {
if ( pMem ) if ( pMem )
{ {
Destruct( pMem ); Destruct( pMem );
} }
CUtlMemoryPool::Free( pMem ); CUtlMemoryPoolBase::Free( pMem );
} }
template< class T > template< class T >
inline void CClassMemoryPool<T>::Clear() inline void CUtlMemoryPool<T>::Clear()
{ {
CUtlRBTree<void *> freeBlocks; CUtlMemoryPoolBase::ClearDestruct( (void (*)( void* ))&Destruct<T> );
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();
} }
@ -399,30 +363,27 @@ inline void CClassMemoryPool<T>::Clear()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \ #define DECLARE_FIXEDSIZE_ALLOCATOR( _class ) \
public: \ 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 ) { 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 " pool"); return s_Allocator.Alloc(size); } \ 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(p); } \ 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(p); } \ inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free((_class*)p); } \
private: \ private: \
static CUtlMemoryPool s_Allocator static CUtlMemoryPool<_class> s_Allocator
#define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \ #define DEFINE_FIXEDSIZE_ALLOCATOR( _class, _initsize, _grow ) \
CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") CUtlMemoryPool<_class> _class::s_Allocator(_initsize, _grow, #_class " CUtlMemoryPool", MemAllocAttribute_Unk2)
#define DEFINE_FIXEDSIZE_ALLOCATOR_ALIGNED( _class, _initsize, _grow, _alignment ) \
CUtlMemoryPool _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", _alignment )
#define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \ #define DECLARE_FIXEDSIZE_ALLOCATOR_MT( _class ) \
public: \ 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 ) { 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 " pool"); return s_Allocator.Alloc(size); } \ 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(p); } \ 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(p); } \ inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { s_Allocator.Free((_class*)p); } \
private: \ private: \
static CMemoryPoolMT s_Allocator static CUtlMemoryPoolMT<_class> s_Allocator
#define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ #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 // Macros that make it simple to make a class use a fixed-size allocator
@ -433,14 +394,14 @@ inline void CClassMemoryPool<T>::Clear()
#define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \ #define DECLARE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class ) \
public: \ 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 ) { 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 " pool"); return s_pAllocator->Alloc(size); } \ 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(p); } \ inline void operator delete( void* p ) { s_pAllocator->Free((_class*)p); } \
private: \ private: \
static CUtlMemoryPool* s_pAllocator static CUtlMemoryPool<_class>* s_pAllocator
#define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \ #define DEFINE_FIXEDSIZE_ALLOCATOR_EXTERNAL( _class, _allocator ) \
CUtlMemoryPool* _class::s_pAllocator = _allocator CUtlMemoryPool<_class>* _class::s_pAllocator = _allocator
template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD > template <int ITEM_SIZE, int ALIGNMENT, int CHUNK_SIZE, class CAllocator, bool GROWMODE, int COMPACT_THRESHOLD >

View File

@ -14,11 +14,12 @@
#endif #endif
#include "tier0/threadtools.h" #include "tier0/threadtools.h"
#include "tier1/utlrbtree.h"
#include "tier1/utlvector.h" #include "tier1/utlvector.h"
#include "tier1/utlbuffer.h" #include "tier1/utlbuffer.h"
#include "tier1/utllinkedlist.h" #include "tier1/utllinkedlist.h"
#include "tier1/stringpool.h" #include "tier1/stringpool.h"
#include "tier1/utlhashtable.h"
#include "tier1/memblockallocator.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -41,7 +42,6 @@ public:
// constructor, destructor // constructor, destructor
CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {} CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) {}
CUtlSymbol( UtlSymId_t id ) : m_Id(id) {} CUtlSymbol( UtlSymId_t id ) : m_Id(id) {}
CUtlSymbol( const char* pStr );
CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {} CUtlSymbol( CUtlSymbol const& sym ) : m_Id(sym.m_Id) {}
// operator= // operator=
@ -49,35 +49,19 @@ public:
// operator== // operator==
bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; } bool operator==( CUtlSymbol const& src ) const { return m_Id == src.m_Id; }
bool operator==( const char* pStr ) const;
// Is valid? // Is valid?
bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; } bool IsValid() const { return m_Id != UTL_INVAL_SYMBOL; }
// Gets at the symbol // Gets at the symbol
operator UtlSymId_t const() const { return m_Id; } operator UtlSymId_t () const { return m_Id; }
// Gets the string associated with the symbol
const char* String( ) const;
// Modules can choose to disable the static symbol table so to prevent accidental use of them.
static void DisableStaticSymbolTable();
protected: protected:
CUtlSymbol( const char* pStr );
bool operator==( const char* pStr ) const;
const char* String( ) const;
UtlSymId_t m_Id; 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: public:
// constructor, destructor // constructor, destructor
CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false ); DLL_CLASS_IMPORT CUtlSymbolTable( int growSize = 0, int initSize = 16, bool caseInsensitive = false );
~CUtlSymbolTable(); DLL_CLASS_IMPORT ~CUtlSymbolTable();
// Finds and/or creates a symbol based on the string // 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 // 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 // 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. // 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 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: protected:
class CStringPoolIndex struct UtlSymTableAltKey
{ {
public: const CUtlSymbolTable* m_pTable;
inline CStringPoolIndex() const char* m_pString;
{ int m_nLength;
}
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.
}; };
class CLess struct UtlSymTableHashFunctor
{ {
public: ptrdiff_t m_ownerOffset;
CLess( int ignored = 0 ) {} // permits default initialization to NULL in CUtlRBTree
bool operator!() const { return false; } UtlSymTableHashFunctor();
bool operator()( const CStringPoolIndex &left, const CStringPoolIndex &right ) const; unsigned int operator()( UtlSymTableAltKey k ) const;
unsigned int operator()( int k ) const;
}; };
// Stores the symbol lookup struct UtlSymTableEqualFunctor
class CTree : public CUtlRBTree<CStringPoolIndex, unsigned short, CLess>
{ {
public: ptrdiff_t m_ownerOffset;
CTree( int growSize, int initSize ) : CUtlRBTree<CStringPoolIndex, unsigned short, CLess>( growSize, initSize ) {}
friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table UtlSymTableEqualFunctor();
bool operator()( int a, int b ) const;
bool operator()( UtlSymTableAltKey a, int b ) const;
bool operator()( int a, UtlSymTableAltKey b ) const;
}; };
struct StringPool_t typedef CUtlHashtable<int, empty_t, UtlSymTableHashFunctor, UtlSymTableEqualFunctor, UtlSymTableAltKey> Hashtable_t;
{ typedef CUtlVector<MemBlockHandle_t> MemBlocksVec_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; bool m_bInsensitive;
mutable unsigned short m_nUserSearchStringHash;
mutable const char* m_pUserSearchString;
// stores the string data
CUtlVector<StringPool_t*> m_StringPools;
uint8 unknown[56];
private:
int FindPoolWithSpace( int len ) const;
const char* StringFromIndex( const CStringPoolIndex &index ) const;
const char* DecoratedStringFromIndex( const CStringPoolIndex &index ) const;
friend class CLess;
friend class CSymbolHash;
}; };
class CUtlSymbolTableMT : public CUtlSymbolTable class CUtlSymbolTableMT : public CUtlSymbolTable
@ -195,25 +162,41 @@ public:
CUtlSymbol AddString( const char* pString, bool* created = NULL ) CUtlSymbol AddString( const char* pString, bool* created = NULL )
{ {
m_lock.LockForWrite(); m_lock.LockForWrite( __FILE__, __LINE__ );
CUtlSymbol result = CUtlSymbolTable::AddString( pString, created ); 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; return result;
} }
CUtlSymbol Find( const char* pString ) const CUtlSymbol Find( const char* pString ) const
{ {
m_lock.LockForWrite(); m_lock.LockForWrite( __FILE__, __LINE__ );
CUtlSymbol result = CUtlSymbolTable::Find( pString ); 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; return result;
} }
const char* String( CUtlSymbol id ) const const char* String( CUtlSymbol id ) const
{ {
m_lock.LockForRead(); m_lock.LockForRead( __FILE__, __LINE__ );
const char *pszResult = CUtlSymbolTable::String( id ); const char *pszResult = CUtlSymbolTable::String( id );
m_lock.UnlockRead(); m_lock.UnlockRead( __FILE__, __LINE__ );
return pszResult; return pszResult;
} }

View File

@ -313,11 +313,9 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT
{ {
unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength ); unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength );
m_Mutex.Lock( __FILE__, __LINE__ ); AUTO_LOCK( m_Mutex );
sym = Find( hash, pString, nLength ); sym = Find( hash, pString, nLength );
m_Mutex.Unlock( __FILE__, __LINE__ );
} }
return sym; return sym;
@ -341,14 +339,12 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT
{ {
unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength ); unsigned int hash = CUtlSymbolLarge_Hash( CASEINSENSITIVE, pString, nLength );
m_Mutex.Lock( __FILE__, __LINE__ ); AUTO_LOCK( m_Mutex );
sym = Find( hash, pString, nLength ); sym = Find( hash, pString, nLength );
if ( !sym.IsValid() ) if ( !sym.IsValid() )
sym = AddString( hash, pString, nLength, created ); sym = AddString( hash, pString, nLength, created );
m_Mutex.Unlock( __FILE__, __LINE__ );
} }
return sym; return sym;
@ -363,25 +359,21 @@ inline CUtlSymbolLarge CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUT
template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE >
inline void CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::RemoveAll() inline void CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::RemoveAll()
{ {
m_Mutex.Lock( __FILE__, __LINE__ ); AUTO_LOCK( m_Mutex );
m_HashTable.RemoveAll(); m_HashTable.RemoveAll();
m_MemBlocks.RemoveAll(); m_MemBlocks.RemoveAll();
m_MemBlockAllocator.RemoveAll(); m_MemBlockAllocator.RemoveAll();
m_Mutex.Unlock( __FILE__, __LINE__ );
} }
template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE > template < bool CASEINSENSITIVE, size_t PAGE_SIZE, class MUTEX_TYPE >
inline void CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Purge() inline void CUtlSymbolTableLargeBase< CASEINSENSITIVE, PAGE_SIZE, MUTEX_TYPE >::Purge()
{ {
m_Mutex.Lock( __FILE__, __LINE__ ); AUTO_LOCK( m_Mutex );
m_HashTable.Purge(); m_HashTable.Purge();
m_MemBlocks.Purge(); m_MemBlocks.Purge();
m_MemBlockAllocator.Purge(); m_MemBlockAllocator.Purge();
m_Mutex.Unlock( __FILE__, __LINE__ );
} }
// Case-sensitive // Case-sensitive

View File

@ -54,18 +54,18 @@ public:
} }
}; };
template < int BUCKET_COUNT, class KEYTYPE = intp > template < class KEYTYPE = intp >
class CUtlTSHashGenericHash class CUtlTSHashGenericHash
{ {
public: public:
static int Hash( const KEYTYPE &key, int nBucketMask ) static int Hash( const KEYTYPE &key, int nBucketMask )
{ {
int nHash = HashIntConventional( (intp)key ); int nHash = HashIntConventional( (intp)key );
if ( BUCKET_COUNT <= USHRT_MAX ) if ( nBucketMask <= USHRT_MAX )
{ {
nHash ^= ( nHash >> 16 ); nHash ^= ( nHash >> 16 );
} }
if ( BUCKET_COUNT <= UCHAR_MAX ) if ( nBucketMask <= UCHAR_MAX )
{ {
nHash ^= ( nHash >> 8 ); nHash ^= ( nHash >> 8 );
} }
@ -78,7 +78,7 @@ public:
} }
}; };
template < int BUCKET_COUNT, class KEYTYPE > template < class KEYTYPE >
class CUtlTSHashUseKeyHashMethod class CUtlTSHashUseKeyHashMethod
{ {
public: 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 class CUtlTSHash
{ {
public: public:
@ -161,33 +161,28 @@ private:
struct HashBucket_t struct HashBucket_t
{ {
CThreadSpinRWLock m_AddLock;
HashFixedData_t *m_pFirst; HashFixedData_t *m_pFirst;
HashFixedData_t *m_pFirstUncommitted; HashFixedData_t *m_pFirstUncommitted;
CThreadSpinRWLock m_AddLock;
}; };
UtlTSHashHandle_t Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement ); UtlTSHashHandle_t Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement );
UtlTSHashHandle_t InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket ); UtlTSHashHandle_t InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket );
CMemoryPoolMT m_EntryMemory; CUtlMemoryPoolBase m_EntryMemory;
HashBucket_t m_aBuckets[BUCKET_COUNT]; HashBucket_t m_aBuckets[BUCKET_COUNT];
bool m_bNeedsCommit; bool m_bNeedsCommit;
#ifdef _DEBUG
CInterlockedInt m_ContentionCheck; CInterlockedInt m_ContentionCheck;
#endif
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Constructor // Purpose: Constructor
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::CUtlTSHash( int nAllocationCount ) : CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::CUtlTSHash( int nAllocationCount ) :
m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, CUtlMemoryPool::GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ), nAlignment ) m_EntryMemory( sizeof( HashFixedData_t ), nAllocationCount, alignof( HashFixedData_t ), UTLMEMORYPOOL_GROW_SLOW, MEM_ALLOC_CLASSNAME( HashFixedData_t ) )
{ {
#ifdef _DEBUG
m_ContentionCheck = 0; m_ContentionCheck = 0;
#endif
m_bNeedsCommit = false; m_bNeedsCommit = false;
for ( int i = 0; i < BUCKET_COUNT; i++ ) for ( int i = 0; i < BUCKET_COUNT; i++ )
{ {
@ -201,8 +196,8 @@ CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::CUtlTSHash( int nAlloca
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Deconstructor // Purpose: Deconstructor
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::~CUtlTSHash() CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::~CUtlTSHash()
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ContentionCheck != 0 ) if ( m_ContentionCheck != 0 )
@ -216,8 +211,8 @@ CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::~CUtlTSHash()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Destroy dynamically allocated hash data. // Purpose: Destroy dynamically allocated hash data.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Purge( void ) inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Purge( void )
{ {
RemoveAll(); RemoveAll();
} }
@ -226,8 +221,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Purge( void
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Returns the number of elements in the hash table // Returns the number of elements in the hash table
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Count() const inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Count() const
{ {
return m_EntryMemory.Count(); return m_EntryMemory.Count();
} }
@ -236,14 +231,14 @@ inline int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Count() cons
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Returns elements in the table // Returns elements in the table
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::GetElements( int nFirstElement, int nCount, UtlTSHashHandle_t *pHandles ) const
{ {
int nIndex = 0; int nIndex = 0;
for ( int i = 0; i < BUCKET_COUNT; i++ ) for ( int i = 0; i < BUCKET_COUNT; i++ )
{ {
const HashBucket_t &bucket = m_aBuckets[ 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 ) for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
{ {
if ( --nFirstElement >= 0 ) if ( --nFirstElement >= 0 )
@ -252,11 +247,11 @@ int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nF
pHandles[ nIndex++ ] = (UtlTSHashHandle_t)pElement; pHandles[ nIndex++ ] = (UtlTSHashHandle_t)pElement;
if ( nIndex >= nCount ) if ( nIndex >= nCount )
{ {
bucket.m_AddLock.UnlockRead( ); bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
return nIndex; return nIndex;
} }
} }
bucket.m_AddLock.UnlockRead( ); bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
} }
return nIndex; return nIndex;
} }
@ -266,8 +261,8 @@ int CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetElements( int nF
// Purpose: Insert data into the hash table given its key (KEYTYPE), // Purpose: Insert data into the hash table given its key (KEYTYPE),
// without a check to see if the element already exists within the tree. // without a check to see if the element already exists within the tree.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::InsertUncommitted( KEYTYPE uiKey, HashBucket_t &bucket )
{ {
m_bNeedsCommit = true; m_bNeedsCommit = true;
HashFixedData_t *pNewElement = static_cast< HashFixedData_t * >( m_EntryMemory.Alloc() ); HashFixedData_t *pNewElement = static_cast< HashFixedData_t * >( m_EntryMemory.Alloc() );
@ -282,8 +277,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
// Purpose: Insert data into the hash table given its key, with // Purpose: Insert data into the hash table given its key, with
// a check to see if the element already exists within the tree. // a check to see if the element already exists within the tree.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Insert( KEYTYPE uiKey, const T &data, bool *pDidInsert )
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ContentionCheck != 0 ) if ( m_ContentionCheck != 0 )
@ -306,7 +301,7 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
return h; return h;
// Now, try again, but only look in uncommitted elements // 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 ); h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
if ( h == InvalidHandle() ) if ( h == InvalidHandle() )
@ -319,12 +314,12 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
} }
} }
bucket.m_AddLock.UnlockWrite( ); bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
return h; return h;
} }
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Insert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor, bool *pDidInsert )
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ContentionCheck != 0 ) if ( m_ContentionCheck != 0 )
@ -346,7 +341,7 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
// Now, try again, but only look in uncommitted elements // Now, try again, but only look in uncommitted elements
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ]; 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 ); h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
if ( h == InvalidHandle() ) if ( h == InvalidHandle() )
@ -361,7 +356,7 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
} }
} }
bucket.m_AddLock.UnlockWrite( ); bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
return h; return h;
} }
@ -370,8 +365,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
// Purpose: Insert data into the hash table given its key // Purpose: Insert data into the hash table given its key
// without a check to see if the element already exists within the tree. // without a check to see if the element already exists within the tree.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, const T &data ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::FastInsert( KEYTYPE uiKey, const T &data )
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ContentionCheck != 0 ) if ( m_ContentionCheck != 0 )
@ -381,15 +376,15 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
#endif #endif
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ]; HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( ); bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket ); UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
CopyConstruct( &Element(h), data ); CopyConstruct( &Element(h), data );
bucket.m_AddLock.UnlockWrite( ); bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
return h; return h;
} }
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::FastInsert( KEYTYPE uiKey, ITSHashConstructor<T> *pConstructor )
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ContentionCheck != 0 ) if ( m_ContentionCheck != 0 )
@ -399,10 +394,10 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
#endif #endif
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ]; HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( ); bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket ); UtlTSHashHandle_t h = InsertUncommitted( uiKey, bucket );
pConstructor->Construct( &Element(h) ); pConstructor->Construct( &Element(h) );
bucket.m_AddLock.UnlockWrite( ); bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
return h; return h;
} }
@ -410,8 +405,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Commits all uncommitted insertions // Purpose: Commits all uncommitted insertions
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( ) inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Commit( )
{ {
// FIXME: Is this legal? Want this to be lock-free // FIXME: Is this legal? Want this to be lock-free
if ( !m_bNeedsCommit ) if ( !m_bNeedsCommit )
@ -425,9 +420,9 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
for ( int i = 0; i < BUCKET_COUNT; i++ ) for ( int i = 0; i < BUCKET_COUNT; i++ )
{ {
HashBucket_t &bucket = m_aBuckets[ 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_pFirst = bucket.m_pFirstUncommitted;
bucket.m_AddLock.UnlockRead( ); bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
} }
m_bNeedsCommit = false; m_bNeedsCommit = false;
@ -441,8 +436,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Commit( )
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Remove a single element from the hash // Purpose: Remove a single element from the hash
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemove( KEYTYPE uiKey ) inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::FindAndRemove( KEYTYPE uiKey )
{ {
if ( m_EntryMemory.Count() == 0 ) if ( m_EntryMemory.Count() == 0 )
return; return;
@ -454,7 +449,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemo
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
HashBucket_t &bucket = m_aBuckets[ iBucket ]; HashBucket_t &bucket = m_aBuckets[ iBucket ];
bucket.m_AddLock.LockForWrite( ); bucket.m_AddLock.LockForWrite( __FILE__, __LINE__ );
HashFixedData_t *pPrev = NULL; HashFixedData_t *pPrev = NULL;
for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext ) for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pPrev = pElement, pElement = pElement->m_pNext )
@ -487,7 +482,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemo
break; break;
} }
bucket.m_AddLock.UnlockWrite( ); bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
#ifdef _DEBUG #ifdef _DEBUG
m_ContentionCheck--; m_ContentionCheck--;
@ -498,8 +493,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::FindAndRemo
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Remove all elements from the hash // Purpose: Remove all elements from the hash
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll( void ) inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::RemoveAll( void )
{ {
m_bNeedsCommit = false; m_bNeedsCommit = false;
if ( m_EntryMemory.Count() == 0 ) if ( m_EntryMemory.Count() == 0 )
@ -514,7 +509,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll(
{ {
HashBucket_t &bucket = m_aBuckets[ i ]; 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 ) for ( HashFixedData_t *pElement = bucket.m_pFirstUncommitted; pElement; pElement = pElement->m_pNext )
{ {
@ -523,7 +518,7 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll(
bucket.m_pFirst = NULL; bucket.m_pFirst = NULL;
bucket.m_pFirstUncommitted = NULL; bucket.m_pFirstUncommitted = NULL;
bucket.m_AddLock.UnlockWrite( ); bucket.m_AddLock.UnlockWrite( __FILE__, __LINE__ );
} }
m_EntryMemory.Clear(); m_EntryMemory.Clear();
@ -536,8 +531,8 @@ inline void CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::RemoveAll(
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Finds an element, but only in the committed elements // Finds an element, but only in the committed elements
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Find( KEYTYPE uiKey, HashFixedData_t *pFirstElement, HashFixedData_t *pLastElement )
{ {
#ifdef _DEBUG #ifdef _DEBUG
if ( m_ContentionCheck != 0 ) if ( m_ContentionCheck != 0 )
@ -558,8 +553,8 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Finds an element, but only in the committed elements // Finds an element, but only in the committed elements
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Find( KEYTYPE uiKey ) inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Find( KEYTYPE uiKey )
{ {
int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK ); int iBucket = HashFuncs::Hash( uiKey, BUCKET_MASK );
const HashBucket_t &bucket = m_aBuckets[iBucket]; const HashBucket_t &bucket = m_aBuckets[iBucket];
@ -567,10 +562,13 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
if ( h != InvalidHandle() ) if ( h != InvalidHandle() )
return h; return h;
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 // Didn't find it in the fast ( committed ) list. Let's try the slow ( uncommitted ) one
bucket.m_AddLock.LockForRead( ); bucket.m_AddLock.LockForRead( __FILE__, __LINE__ );
h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst ); h = Find( uiKey, bucket.m_pFirstUncommitted, bucket.m_pFirst );
bucket.m_AddLock.UnlockRead( ); bucket.m_AddLock.UnlockRead( __FILE__, __LINE__ );
}
return h; return h;
} }
@ -579,41 +577,41 @@ inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Return data given a hash handle. // Purpose: Return data given a hash handle.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash ) inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Element( UtlTSHashHandle_t hHash )
{ {
return ((HashFixedData_t *)hHash)->m_Data; return ((HashFixedData_t *)hHash)->m_Data;
} }
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::Element( UtlTSHashHandle_t hHash ) const inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::Element( UtlTSHashHandle_t hHash ) const
{ {
return ((HashFixedData_t *)hHash)->m_Data; return ((HashFixedData_t *)hHash)->m_Data;
} }
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash ) inline T &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::operator[]( UtlTSHashHandle_t hHash )
{ {
return ((HashFixedData_t *)hHash)->m_Data; return ((HashFixedData_t *)hHash)->m_Data;
} }
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::operator[]( UtlTSHashHandle_t hHash ) const inline T const &CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::operator[]( UtlTSHashHandle_t hHash ) const
{ {
return ((HashFixedData_t *)hHash)->m_Data; return ((HashFixedData_t *)hHash)->m_Data;
} }
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline KEYTYPE CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::GetID( UtlTSHashHandle_t hHash ) const inline KEYTYPE CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::GetID( UtlTSHashHandle_t hHash ) const
{ {
return ((HashFixedData_t *)hHash)->m_uiKey; return ((HashFixedData_t *)hHash)->m_uiKey;
} }
// Convert element * to hashHandle // Convert element * to hashHandle
template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs, int nAlignment> template<class T, int BUCKET_COUNT, class KEYTYPE, class HashFuncs>
inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs,nAlignment>::ElementPtrToHandle( T* pElement ) const inline UtlTSHashHandle_t CUtlTSHash<T,BUCKET_COUNT,KEYTYPE,HashFuncs>::ElementPtrToHandle( T* pElement ) const
{ {
Assert( pElement ); Assert( pElement );
HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) ); HashFixedData_t *pFixedData = (HashFixedData_t*)( (uint8*)pElement - offsetof( HashFixedData_t, m_Data ) );

View File

@ -1,316 +0,0 @@
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "mempool.h"
#include <stdio.h>
#ifdef __APPLE__
#include <sys/malloc.h>
#else
#include <malloc.h>
#endif
#include <memory.h>
#include "tier0/dbg.h"
#include <ctype.h>
#include "tier1/strtools.h"
// Should be last include
#include "tier0/memdbgon.h"
MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0;
//-----------------------------------------------------------------------------
// Error reporting... (debug only)
//-----------------------------------------------------------------------------
void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func )
{
g_ReportFunc = func;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment )
{
#ifdef _X360
if( numElements > 0 && growMode != GROW_NONE )
{
numElements = 1;
}
#endif
m_nAlignment = ( nAlignment != 0 ) ? nAlignment : 1;
Assert( IsPowerOfTwo( m_nAlignment ) );
m_BlockSize = blockSize < (int)sizeof(void*) ? sizeof(void*) : blockSize;
m_BlockSize = AlignValue( m_BlockSize, m_nAlignment );
m_BlocksPerBlob = numElements;
m_PeakAlloc = 0;
m_GrowMode = growMode;
if ( !pszAllocOwner )
{
pszAllocOwner = __FILE__;
}
m_pszAllocOwner = pszAllocOwner;
Init();
AddNewBlob();
}
//-----------------------------------------------------------------------------
// Purpose: Frees the memory contained in the mempool, and invalidates it for
// any further use.
// Input : *memPool - the mempool to shutdown
//-----------------------------------------------------------------------------
CUtlMemoryPool::~CUtlMemoryPool()
{
if (m_BlocksAllocated > 0)
{
ReportLeaks();
}
Clear();
}
//-----------------------------------------------------------------------------
// Resets the pool
//-----------------------------------------------------------------------------
void CUtlMemoryPool::Init()
{
m_NumBlobs = 0;
m_BlocksAllocated = 0;
m_pHeadOfFreeList = 0;
m_BlobHead.m_pNext = m_BlobHead.m_pPrev = &m_BlobHead;
}
//-----------------------------------------------------------------------------
// Frees everything
//-----------------------------------------------------------------------------
void CUtlMemoryPool::Clear()
{
// Free everything..
CBlob *pNext;
for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pNext )
{
pNext = pCur->m_pNext;
free( pCur );
}
Init();
}
//-----------------------------------------------------------------------------
// Purpose: Reports memory leaks
//-----------------------------------------------------------------------------
void CUtlMemoryPool::ReportLeaks()
{
if (!g_ReportFunc)
return;
g_ReportFunc("Memory leak: mempool blocks left in memory: %d\n", m_BlocksAllocated);
#ifdef _DEBUG
// walk and destroy the free list so it doesn't intefere in the scan
while (m_pHeadOfFreeList != NULL)
{
void *next = *((void**)m_pHeadOfFreeList);
memset(m_pHeadOfFreeList, 0, m_BlockSize);
m_pHeadOfFreeList = next;
}
g_ReportFunc("Dumping memory: \'");
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
// scan the memory block and dump the leaks
char *scanPoint = (char *)pCur->m_Data;
char *scanEnd = pCur->m_Data + pCur->m_NumBytes;
bool needSpace = false;
while (scanPoint < scanEnd)
{
// search for and dump any strings
if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint))
{
g_ReportFunc("%c", *scanPoint);
needSpace = true;
}
else if (needSpace)
{
needSpace = false;
g_ReportFunc(" ");
}
scanPoint++;
}
}
g_ReportFunc("\'\n");
#endif // _DEBUG
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CUtlMemoryPool::AddNewBlob()
{
MEM_ALLOC_CREDIT_(m_pszAllocOwner);
int sizeMultiplier;
if( m_GrowMode == GROW_SLOW )
{
sizeMultiplier = 1;
}
else
{
if ( m_GrowMode == GROW_NONE )
{
// Can only have one allocation when we're in this mode
if( m_NumBlobs != 0 )
{
Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" );
return;
}
}
// GROW_FAST and GROW_NONE use this.
sizeMultiplier = m_NumBlobs + 1;
}
// maybe use something other than malloc?
int nElements = m_BlocksPerBlob * sizeMultiplier;
int blobSize = m_BlockSize * nElements;
CBlob *pBlob = (CBlob*)malloc( sizeof(CBlob) - 1 + blobSize + ( m_nAlignment - 1 ) );
Assert( pBlob );
// Link it in at the end of the blob list.
pBlob->m_NumBytes = blobSize;
pBlob->m_pNext = &m_BlobHead;
pBlob->m_pPrev = pBlob->m_pNext->m_pPrev;
pBlob->m_pNext->m_pPrev = pBlob->m_pPrev->m_pNext = pBlob;
// setup the free list
m_pHeadOfFreeList = AlignValue( pBlob->m_Data, m_nAlignment );
Assert (m_pHeadOfFreeList);
void **newBlob = (void**)m_pHeadOfFreeList;
for (int j = 0; j < nElements-1; j++)
{
newBlob[0] = (char*)newBlob + m_BlockSize;
newBlob = (void**)newBlob[0];
}
// null terminate list
newBlob[0] = NULL;
m_NumBlobs++;
}
void* CUtlMemoryPool::Alloc()
{
return Alloc( m_BlockSize );
}
void* CUtlMemoryPool::AllocZero()
{
return AllocZero( m_BlockSize );
}
//-----------------------------------------------------------------------------
// Purpose: Allocs a single block of memory from the pool.
// Input : amount -
//-----------------------------------------------------------------------------
void *CUtlMemoryPool::Alloc( size_t amount )
{
void *returnBlock;
if ( amount > (unsigned int)m_BlockSize )
return NULL;
if( !m_pHeadOfFreeList )
{
// returning NULL is fine in GROW_NONE
if( m_GrowMode == GROW_NONE )
{
//Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with GROW_NONE" );
return NULL;
}
// overflow
AddNewBlob();
// still failure, error out
if( !m_pHeadOfFreeList )
{
Assert( !"CUtlMemoryPool::Alloc: ran out of memory" );
return NULL;
}
}
m_BlocksAllocated++;
m_PeakAlloc = MAX(m_PeakAlloc, m_BlocksAllocated);
returnBlock = m_pHeadOfFreeList;
// move the pointer the next block
m_pHeadOfFreeList = *((void**)m_pHeadOfFreeList);
return returnBlock;
}
//-----------------------------------------------------------------------------
// Purpose: Allocs a single block of memory from the pool, zeroes the memory before returning
// Input : amount -
//-----------------------------------------------------------------------------
void *CUtlMemoryPool::AllocZero( size_t amount )
{
void *mem = Alloc( amount );
if ( mem )
{
V_memset( mem, 0x00, amount );
}
return mem;
}
//-----------------------------------------------------------------------------
// Purpose: Frees a block of memory
// Input : *memBlock - the memory to free
//-----------------------------------------------------------------------------
void CUtlMemoryPool::Free( void *memBlock )
{
if ( !memBlock )
return; // trying to delete NULL pointer, ignore
#ifdef _DEBUG
// check to see if the memory is from the allocated range
bool bOK = false;
for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext )
{
if (memBlock >= pCur->m_Data && (char*)memBlock < (pCur->m_Data + pCur->m_NumBytes))
{
bOK = true;
}
}
Assert (bOK);
#endif // _DEBUG
#ifdef _DEBUG
// invalidate the memory
memset( memBlock, 0xDD, m_BlockSize );
#endif
m_BlocksAllocated--;
// make the block point to the first item in the list
*((void**)memBlock) = m_pHeadOfFreeList;
// the list head is now the new block
m_pHeadOfFreeList = memBlock;
}