diff --git a/public/datamap.h b/public/datamap.h index d4eee4ee..2f4edbf5 100644 --- a/public/datamap.h +++ b/public/datamap.h @@ -110,7 +110,7 @@ DECLARE_FIELD_SIZE( FIELD_MODELNAME, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_SOUNDNAME, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_EHANDLE, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_CLASSPTR, sizeof(void*)) -DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(int)) +DECLARE_FIELD_SIZE( FIELD_EDICT, sizeof(void*)) DECLARE_FIELD_SIZE( FIELD_POSITION_VECTOR, 3 * sizeof(float)) DECLARE_FIELD_SIZE( FIELD_TIME, sizeof(float)) DECLARE_FIELD_SIZE( FIELD_TICK, sizeof(int)) diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 0e46b970..701c62ff 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -525,6 +525,16 @@ typedef void * HINSTANCE; #error #endif +// !!! NOTE: if you get a compile error here, you are using VALIGNOF on an abstract type :NOTE !!! +#define VALIGNOF_PORTABLE( type ) ( sizeof( AlignOf_t ) - sizeof( type ) ) + +#if defined( COMPILER_GCC ) || defined( COMPILER_MSVC ) +#define VALIGNOF( type ) __alignof( type ) +#define VALIGNOF_TEMPLATE_SAFE( type ) VALIGNOF_PORTABLE( type ) +#else +#error "PORT: Code only tested with MSVC! Must validate with new compiler, and use built-in keyword if available." +#endif + // Pull in the /analyze code annotations. #include "annotations.h" diff --git a/public/tier1/datamanager.h b/public/tier1/datamanager.h index 19342a39..03403248 100644 --- a/public/tier1/datamanager.h +++ b/public/tier1/datamanager.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -65,6 +65,8 @@ public: // ----------------------------------------------------------------------------- + void SetFreeOnDestruct( bool value ) { m_freeOnDestruct = value; } + // Debugging only!!!! void GetLRUHandleList( CUtlVector< memhandle_t >& list ); void GetLockHandleList( CUtlVector< memhandle_t >& list ); @@ -77,6 +79,7 @@ protected: void *GetResource_NoLock( memhandle_t handle ); void *GetResource_NoLockNoLRUTouch( memhandle_t handle ); void *LockResource( memhandle_t handle ); + void *LockResourceReturnCount( int *pCount, memhandle_t handle ); // NOTE: you must call this from the destructor of the derived class! (will assert otherwise) void FreeAllLists() { FlushAll(); m_listsAreFreed = true; } @@ -123,7 +126,8 @@ protected: unsigned short m_lockList; unsigned short m_freeList; unsigned short m_listsAreFreed : 1; - unsigned short m_unused : 15; + unsigned short m_freeOnDestruct : 1; + unsigned short m_unused : 14; }; @@ -139,7 +143,10 @@ public: ~CDataManager() { // NOTE: This must be called in all implementations of CDataManager - FreeAllLists(); + if ( m_freeOnDestruct ) + { + FreeAllLists(); + } } // Use GetData() to translate pointer to LOCK_TYPE @@ -154,6 +161,17 @@ public: return NULL; } + LOCK_TYPE LockResourceReturnCount( int *pCount, memhandle_t hMem ) + { + void *pLock = BaseClass::LockResourceReturnCount( pCount, hMem ); + if ( pLock ) + { + return StoragePointer(pLock)->GetData(); + } + + return NULL; + } + // Use GetData() to translate pointer to LOCK_TYPE LOCK_TYPE GetResource_NoLock( memhandle_t hMem ) { @@ -181,8 +199,9 @@ public: memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false ) { BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); - unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); + AUTO_LOCK_( CDataManagerBase, *this ); + unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() ); } @@ -251,7 +270,7 @@ private: inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle ) { - uintp fullWord = (uintp)handle; + unsigned int fullWord = (unsigned int)reinterpret_cast( handle ); unsigned short serial = fullWord>>16; unsigned short index = fullWord & 0xFFFF; index--; diff --git a/public/tier1/mempool.h b/public/tier1/mempool.h index 26b9ea23..e01bc9ef 100644 --- a/public/tier1/mempool.h +++ b/public/tier1/mempool.h @@ -1,4 +1,4 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // @@ -30,27 +30,19 @@ typedef void (*MemoryPoolReportFunc_t)( PRINTF_FORMAT_STRING char const* pMsg, ... ); -// Ways a 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. -}; - class CUtlMemoryPool { public: - // !KLUDGE! For legacy code support, import the global enum into this scope + // Ways the memory pool can grow when it needs to make a new blob. enum MemoryPoolGrowType_t { - GROW_NONE=UTLMEMORYPOOL_GROW_NONE, - GROW_FAST=UTLMEMORYPOOL_GROW_FAST, - GROW_SLOW=UTLMEMORYPOOL_GROW_SLOW + 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 = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); + CUtlMemoryPool( int blockSize, int numElements, int growMode = GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0 ); ~CUtlMemoryPool(); void* Alloc(); // Allocate the element size you specified in the constructor. @@ -66,8 +58,12 @@ public: static void SetErrorReportFunc( MemoryPoolReportFunc_t func ); // returns number of allocated blocks - int Count() { return m_BlocksAllocated; } - int PeakCount() { return m_PeakAlloc; } + int Count() const { return m_BlocksAllocated; } + int PeakCount() const { return m_PeakAlloc; } + int BlockSize() const { return m_BlockSize; } + int Size() const; + + bool IsAllocationWithinPool( void *pMem ) const; protected: class CBlob @@ -89,14 +85,13 @@ protected: int m_GrowMode; // GROW_ enum. - // Put m_BlocksAllocated in front of m_pHeadOfFreeList for better - // packing on 64-bit where pointers are 8-byte aligned. int m_BlocksAllocated; - // FIXME: Change m_ppMemBlob into a growable array? - void *m_pHeadOfFreeList; int m_PeakAlloc; unsigned short m_nAlignment; unsigned short m_NumBlobs; + // Group up pointers at the end of the class to avoid padding bloat + // FIXME: Change m_ppMemBlob into a growable array? + void *m_pHeadOfFreeList; const char * m_pszAllocOwner; // CBlob could be not a multiple of 4 bytes so stuff it at the end here to keep us otherwise aligned CBlob m_BlobHead; @@ -106,13 +101,12 @@ protected: //----------------------------------------------------------------------------- -// +// Multi-thread/Thread Safe Memory Class //----------------------------------------------------------------------------- class CMemoryPoolMT : public CUtlMemoryPool { public: - // MoeMod : add alignment - CMemoryPoolMT(int blockSize, int numElements, int growMode = UTLMEMORYPOOL_GROW_FAST, const char *pszAllocOwner = NULL, int nAlignment = 0) : CUtlMemoryPool( blockSize, numElements, growMode, pszAllocOwner, nAlignment) {} + 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(); } @@ -136,15 +130,8 @@ template< class T > class CClassMemoryPool : public CUtlMemoryPool { public: - // MoeMod : bad default align here, should be alignof(T) - CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = alignof(T) ) : - CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) { - #ifdef PLATFORM_64BITS - COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 64 ); - #else - COMPILE_TIME_ASSERT( sizeof(CUtlMemoryPool) == 48 ); - #endif - } + CClassMemoryPool(int numElements, int growMode = GROW_FAST, int nAlignment = 0 ) : + CUtlMemoryPool( sizeof(T), numElements, growMode, MEM_ALLOC_CLASSNAME(T), nAlignment ) {} T* Alloc(); T* AllocZero(); @@ -153,16 +140,15 @@ public: void Clear(); }; - //----------------------------------------------------------------------------- -// Specialized pool for aligned data management (e.g., Xbox cubemaps) +// Specialized pool for aligned data management (e.g., Xbox textures) //----------------------------------------------------------------------------- -template +template class CAlignedMemPool { enum { - BLOCK_SIZE = ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) > 8 ? ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ) : 8 + BLOCK_SIZE = COMPILETIME_MAX( ALIGN_VALUE( ITEM_SIZE, ALIGNMENT ), 8 ), }; public: @@ -174,13 +160,13 @@ public: static int __cdecl CompareChunk( void * const *ppLeft, void * const *ppRight ); void Compact(); - int NumTotal() { return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } - int NumAllocated() { return NumTotal() - m_nFree; } - int NumFree() { return m_nFree; } + int NumTotal() { AUTO_LOCK( m_mutex ); return m_Chunks.Count() * ( CHUNK_SIZE / BLOCK_SIZE ); } + int NumAllocated() { AUTO_LOCK( m_mutex ); return NumTotal() - m_nFree; } + int NumFree() { AUTO_LOCK( m_mutex ); return m_nFree; } - int BytesTotal() { return NumTotal() * BLOCK_SIZE; } - int BytesAllocated() { return NumAllocated() * BLOCK_SIZE; } - int BytesFree() { return NumFree() * BLOCK_SIZE; } + int BytesTotal() { AUTO_LOCK( m_mutex ); return NumTotal() * BLOCK_SIZE; } + int BytesAllocated() { AUTO_LOCK( m_mutex ); return NumAllocated() * BLOCK_SIZE; } + int BytesFree() { AUTO_LOCK( m_mutex ); return NumFree() * BLOCK_SIZE; } int ItemSize() { return ITEM_SIZE; } int BlockSize() { return BLOCK_SIZE; } @@ -197,7 +183,9 @@ private: FreeBlock_t * m_pFirstFree; int m_nFree; CAllocator m_Allocator; - float m_TimeLastCompact; + double m_TimeLastCompact; + + CThreadFastMutex m_mutex; }; //----------------------------------------------------------------------------- @@ -228,7 +216,7 @@ public: void Purge() { - T *p; + T *p = NULL; while ( m_AvailableObjects.PopItem( &p ) ) { delete p; @@ -237,7 +225,7 @@ public: T *GetObject( bool bCreateNewIfEmpty = bDefCreateNewIfEmpty ) { - T *p; + T *p = NULL; if ( !m_AvailableObjects.PopItem( &p ) ) { p = ( bCreateNewIfEmpty ) ? new T : NULL; @@ -255,6 +243,98 @@ private: }; //----------------------------------------------------------------------------- +// Fixed budget pool with overflow to malloc +//----------------------------------------------------------------------------- +template +class CFixedBudgetMemoryPool +{ +public: + CFixedBudgetMemoryPool() + { + m_pBase = m_pLimit = 0; + COMPILE_TIME_ASSERT( ITEM_SIZE % 4 == 0 ); + } + + bool Owns( void *p ) + { + return ( p >= m_pBase && p < m_pLimit ); + } + + void *Alloc() + { + MEM_ALLOC_CREDIT_CLASS(); +#ifndef USE_MEM_DEBUG + if ( !m_pBase ) + { + LOCAL_THREAD_LOCK(); + if ( !m_pBase ) + { + byte *pMemory = m_pBase = (byte *)malloc( ITEM_COUNT * ITEM_SIZE ); + m_pLimit = m_pBase + ( ITEM_COUNT * ITEM_SIZE ); + + for ( int i = 0; i < ITEM_COUNT; i++ ) + { + m_freeList.Push( (TSLNodeBase_t *)pMemory ); + pMemory += ITEM_SIZE; + } + } + } + + void *p = m_freeList.Pop(); + if ( p ) + return p; +#endif + return malloc( ITEM_SIZE ); + } + + void Free( void *p ) + { +#ifndef USE_MEM_DEBUG + if ( Owns( p ) ) + m_freeList.Push( (TSLNodeBase_t *)p ); + else +#endif + free( p ); + } + + void Clear() + { +#ifndef USE_MEM_DEBUG + if ( m_pBase ) + { + free( m_pBase ); + } + m_pBase = m_pLimit = 0; + Construct( &m_freeList ); +#endif + } + + bool IsEmpty() + { +#ifndef USE_MEM_DEBUG + if ( m_pBase && m_freeList.Count() != ITEM_COUNT ) + return false; +#endif + return true; + } + + enum + { + ITEM_SIZE = ALIGN_VALUE( PROVIDED_ITEM_SIZE, TSLIST_NODE_ALIGNMENT ) + }; + + CTSListBase m_freeList; + byte *m_pBase; + byte *m_pLimit; +}; + +#define BIND_TO_FIXED_BUDGET_POOL( poolName ) \ + inline void* operator new( size_t size ) { return poolName.Alloc(); } \ + inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return poolName.Alloc(); } \ + inline void operator delete( void* p ) { poolName.Free(p); } \ + inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { poolName.Free(p); } + +//----------------------------------------------------------------------------- template< class T > @@ -263,7 +343,7 @@ inline T* CClassMemoryPool::Alloc() T *pRet; { - MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + MEM_ALLOC_CREDIT_CLASS(); pRet = (T*)CUtlMemoryPool::Alloc(); } @@ -280,7 +360,7 @@ inline T* CClassMemoryPool::AllocZero() T *pRet; { - MEM_ALLOC_CREDIT_(MEM_ALLOC_CLASSNAME(T)); + MEM_ALLOC_CREDIT_CLASS(); pRet = (T*)CUtlMemoryPool::AllocZero(); } @@ -305,7 +385,7 @@ inline void CClassMemoryPool::Free(T *pMem) template< class T > inline void CClassMemoryPool::Clear() { - CUtlRBTree freeBlocks; + CUtlRBTree freeBlocks; SetDefLessFunc( freeBlocks ); void *pCurFree = m_pHeadOfFreeList; @@ -317,9 +397,9 @@ inline void CClassMemoryPool::Clear() for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) { - // MoeMod : should realign to real data. - T *p = (T *)AlignValue( pCur->m_Data, m_nAlignment ); - T *pLimit = (T *)(pCur->m_Data + pCur->m_NumBytes); + int nElements = pCur->m_NumBytes / this->m_BlockSize; + T *p = ( T * ) AlignValue( pCur->m_Data, this->m_nAlignment ); + T *pLimit = p + nElements; while ( p < pLimit ) { if ( freeBlocks.Find( p ) == freeBlocks.InvalidIndex() ) @@ -334,6 +414,9 @@ inline void CClassMemoryPool::Clear() } + + + //----------------------------------------------------------------------------- // Macros that make it simple to make a class use a fixed-size allocator // Put DECLARE_FIXEDSIZE_ALLOCATOR in the private section of a class, @@ -364,7 +447,7 @@ inline void CClassMemoryPool::Clear() static CMemoryPoolMT s_Allocator #define DEFINE_FIXEDSIZE_ALLOCATOR_MT( _class, _initsize, _grow ) \ - CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool", alignof(_class)) + CMemoryPoolMT _class::s_Allocator(sizeof(_class), _initsize, _grow, #_class " pool") //----------------------------------------------------------------------------- // Macros that make it simple to make a class use a fixed-size allocator @@ -385,21 +468,30 @@ inline void CClassMemoryPool::Clear() CUtlMemoryPool* _class::s_pAllocator = _allocator -template -inline CAlignedMemPool::CAlignedMemPool() +template +inline CAlignedMemPool::CAlignedMemPool() : m_pFirstFree( 0 ), m_nFree( 0 ), m_TimeLastCompact( 0 ) { - COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); - COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); + // These COMPILE_TIME_ASSERT checks need to be in individual scopes to avoid build breaks + // on MacOS and Linux due to a gcc bug. + { COMPILE_TIME_ASSERT( sizeof( FreeBlock_t ) >= BLOCK_SIZE ); } + { COMPILE_TIME_ASSERT( ALIGN_VALUE( sizeof( FreeBlock_t ), ALIGNMENT ) == sizeof( FreeBlock_t ) ); } } -template -inline void *CAlignedMemPool::Alloc() +template +inline void *CAlignedMemPool::Alloc() { + AUTO_LOCK( m_mutex ); + if ( !m_pFirstFree ) { + if ( !GROWMODE && m_Chunks.Count() ) + { + return NULL; + } + FreeBlock_t *pNew = (FreeBlock_t *)m_Allocator.Alloc( CHUNK_SIZE ); Assert( (unsigned)pNew % ALIGNMENT == 0 ); m_Chunks.AddToTail( pNew ); @@ -420,9 +512,11 @@ inline void *CAlignedMemPool -inline void CAlignedMemPool::Free( void *p ) +template +inline void CAlignedMemPool::Free( void *p ) { + AUTO_LOCK( m_mutex ); + // Insertion sort to encourage allocation clusters in chunks FreeBlock_t *pFree = ((FreeBlock_t *)p); FreeBlock_t *pCur = m_pFirstFree; @@ -448,9 +542,9 @@ inline void CAlignedMemPool= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD ) { - float time = Plat_FloatTime(); - float compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; - if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < Plat_FloatTime() ) + double time = Plat_FloatTime(); + double compactTime = ( m_nFree >= ( CHUNK_SIZE / BLOCK_SIZE ) * COMPACT_THRESHOLD * 4 ) ? 15.0 : 30.0; + if ( m_TimeLastCompact > time || m_TimeLastCompact + compactTime < time ) { Compact(); m_TimeLastCompact = time; @@ -458,14 +552,14 @@ inline void CAlignedMemPool -inline int __cdecl CAlignedMemPool::CompareChunk( void * const *ppLeft, void * const *ppRight ) +template +inline int __cdecl CAlignedMemPool::CompareChunk( void * const *ppLeft, void * const *ppRight ) { - return (int)(((uintp)*ppLeft) - ((uintp)*ppRight)); + return static_cast( (intp)*ppLeft - (intp)*ppRight ); } -template -inline void CAlignedMemPool::Compact() +template +inline void CAlignedMemPool::Compact() { FreeBlock_t *pCur = m_pFirstFree; FreeBlock_t *pPrev = NULL; diff --git a/tier1/datamanager.cpp b/tier1/datamanager.cpp index 1fe33f32..922a1262 100644 --- a/tier1/datamanager.cpp +++ b/tier1/datamanager.cpp @@ -1,4 +1,4 @@ - +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -9,8 +9,14 @@ #include "basetypes.h" #include "datamanager.h" +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + DECLARE_POINTER_HANDLE( memhandle_t ); +#define AUTO_LOCK_DM() AUTO_LOCK_( CDataManagerBase, *this ) + CDataManagerBase::CDataManagerBase( unsigned int maxSize ) { m_targetMemorySize = maxSize; @@ -19,11 +25,12 @@ CDataManagerBase::CDataManagerBase( unsigned int maxSize ) m_lockList = m_memoryLists.CreateList(); m_freeList = m_memoryLists.CreateList(); m_listsAreFreed = 0; + m_freeOnDestruct = 1; } CDataManagerBase::~CDataManagerBase() { - Assert( m_listsAreFreed ); + Assert( !m_freeOnDestruct || m_listsAreFreed ); } void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize ) @@ -43,7 +50,7 @@ unsigned int CDataManagerBase::FlushAllUnlocked() Lock(); int nFlush = m_memoryLists.Count( m_lruList ); - void **pScratch = (void **)_alloca( nFlush * sizeof(void *) ); + void **pScratch = (void **)stackalloc( nFlush * sizeof(void *) ); CUtlVector destroyList( pScratch, nFlush ); unsigned nBytesInitial = MemUsed_Inline(); @@ -80,7 +87,7 @@ unsigned int CDataManagerBase::FlushAll() Lock(); int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList ); - void **pScratch = (void **)_alloca( nFlush * sizeof(void *) ); + void **pScratch = (void **) stackalloc( nFlush * sizeof(void *) ); CUtlVector destroyList( pScratch, nFlush ); unsigned result = MemUsed_Inline(); @@ -120,8 +127,7 @@ unsigned int CDataManagerBase::FlushAll() unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge ) { unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge; - // Check for underflow - if ( MemUsed_Inline() < nBytesToPurge ) + if ( nBytesToPurge > MemUsed_Inline() ) nTargetSize = 0; unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize; return EnsureCapacity( nImpliedCapacity ); @@ -151,8 +157,7 @@ void CDataManagerBase::DestroyResource( memhandle_t handle ) void *CDataManagerBase::LockResource( memhandle_t handle ) { - AUTO_LOCK( *this ); - + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -169,9 +174,29 @@ void *CDataManagerBase::LockResource( memhandle_t handle ) return NULL; } +void *CDataManagerBase::LockResourceReturnCount( int *pCount, memhandle_t handle ) +{ + AUTO_LOCK_DM(); + unsigned short memoryIndex = FromHandle(handle); + if ( memoryIndex != m_memoryLists.InvalidIndex() ) + { + if ( m_memoryLists[memoryIndex].lockCount == 0 ) + { + m_memoryLists.Unlink( m_lruList, memoryIndex ); + m_memoryLists.LinkToTail( m_lockList, memoryIndex ); + } + Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1); + *pCount = ++m_memoryLists[memoryIndex].lockCount; + return m_memoryLists[memoryIndex].pStore; + } + + *pCount = 0; + return NULL; +} + int CDataManagerBase::UnlockResource( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -193,7 +218,7 @@ int CDataManagerBase::UnlockResource( memhandle_t handle ) void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -205,7 +230,7 @@ void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle ) void *CDataManagerBase::GetResource_NoLock( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -217,13 +242,13 @@ void *CDataManagerBase::GetResource_NoLock( memhandle_t handle ) void CDataManagerBase::TouchResource( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); TouchByIndex( FromHandle(handle) ); } void CDataManagerBase::MarkAsStale( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() ) { @@ -237,7 +262,7 @@ void CDataManagerBase::MarkAsStale( memhandle_t handle ) int CDataManagerBase::BreakLock( memhandle_t handle ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); unsigned short memoryIndex = FromHandle(handle); if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount ) { @@ -253,7 +278,7 @@ int CDataManagerBase::BreakLock( memhandle_t handle ) int CDataManagerBase::BreakAllLocks() { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); int nBroken = 0; int node; int nextNode; @@ -275,7 +300,7 @@ int CDataManagerBase::BreakAllLocks() unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); int memoryIndex = m_memoryLists.Head(m_freeList); unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList; if ( memoryIndex != m_memoryLists.InvalidIndex() ) @@ -298,7 +323,7 @@ unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked ) memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize ) { - AUTO_LOCK( *this ); + AUTO_LOCK_DM(); resource_lru_element_t &mem = m_memoryLists[memoryIndex]; mem.pStore = pStore; m_memUsed += realSize; @@ -322,7 +347,7 @@ memhandle_t CDataManagerBase::ToHandle( unsigned short index ) unsigned int hiword = m_memoryLists.Element(index).serial; hiword <<= 16; index++; - return (memhandle_t)( hiword|index ); + return reinterpret_cast< memhandle_t >( (uintp)( hiword|index ) ); } unsigned int CDataManagerBase::TargetSize() diff --git a/tier1/mempool.cpp b/tier1/mempool.cpp index fc3fb9b1..9cb9e223 100644 --- a/tier1/mempool.cpp +++ b/tier1/mempool.cpp @@ -1,24 +1,23 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// +//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // //===========================================================================// -#include "mempool.h" +#include "tier1/mempool.h" #include -#ifdef OSX -#include -#else -#include -#endif #include #include "tier0/dbg.h" #include #include "tier1/strtools.h" +#ifndef _PS3 +#include +#endif + // Should be last include #include "tier0/memdbgon.h" - + MemoryPoolReportFunc_t CUtlMemoryPool::g_ReportFunc = 0; //----------------------------------------------------------------------------- @@ -36,7 +35,7 @@ void CUtlMemoryPool::SetErrorReportFunc( MemoryPoolReportFunc_t func ) CUtlMemoryPool::CUtlMemoryPool( int blockSize, int numElements, int growMode, const char *pszAllocOwner, int nAlignment ) { #ifdef _X360 - if( numElements > 0 && growMode != UTLMEMORYPOOL_GROW_NONE ) + if( numElements > 0 && growMode != GROW_NONE ) { numElements = 1; } @@ -100,18 +99,40 @@ void CUtlMemoryPool::Clear() Init(); } + //----------------------------------------------------------------------------- -// Purpose: Reports memory leaks +// Is an allocation within the pool? //----------------------------------------------------------------------------- +bool CUtlMemoryPool::IsAllocationWithinPool( void *pMem ) const +{ + for( CBlob *pCur = m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur = pCur->m_pNext ) + { + // Is the allocation within the blob? + if ( ( pMem < pCur->m_Data ) || ( pMem >= pCur->m_Data + pCur->m_NumBytes ) ) + continue; + + // Make sure the allocation is on a block boundary + intp pFirstAllocation = AlignValue( ( intp ) pCur->m_Data, m_nAlignment ); + + intp nOffset = (intp)pMem - pFirstAllocation; + return ( nOffset % m_BlockSize ) == 0; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Reports memory leaks +//----------------------------------------------------------------------------- void CUtlMemoryPool::ReportLeaks() { +#ifdef _DEBUG 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) { @@ -132,7 +153,7 @@ void CUtlMemoryPool::ReportLeaks() while (scanPoint < scanEnd) { // search for and dump any strings - if ((unsigned)(*scanPoint + 1) <= 256 && isprint(*scanPoint)) + if ((unsigned)(*scanPoint + 1) <= 256 && V_isprint(*scanPoint)) { g_ReportFunc("%c", *scanPoint); needSpace = true; @@ -161,18 +182,18 @@ void CUtlMemoryPool::AddNewBlob() int sizeMultiplier; - if( m_GrowMode == UTLMEMORYPOOL_GROW_SLOW ) + if( m_GrowMode == GROW_SLOW ) { sizeMultiplier = 1; } else { - if ( m_GrowMode == UTLMEMORYPOOL_GROW_NONE ) + if ( m_GrowMode == GROW_NONE ) { // Can only have one allocation when we're in this mode if( m_NumBlobs != 0 ) { - Assert( !"CUtlMemoryPool::AddNewBlob: mode == UTLMEMORYPOOL_GROW_NONE" ); + Assert( !"CUtlMemoryPool::AddNewBlob: mode == GROW_NONE" ); return; } } @@ -230,15 +251,15 @@ void *CUtlMemoryPool::Alloc( size_t amount ) { void *returnBlock; - if ( amount > (unsigned int)m_BlockSize ) + if ( amount > (size_t)m_BlockSize ) return NULL; - if( !m_pHeadOfFreeList ) + if ( !m_pHeadOfFreeList ) { - // returning NULL is fine in UTLMEMORYPOOL_GROW_NONE - if( m_GrowMode == UTLMEMORYPOOL_GROW_NONE ) + // returning NULL is fine in GROW_NONE + if ( m_GrowMode == GROW_NONE && m_NumBlobs > 0 ) { - //Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with UTLMEMORYPOOL_GROW_NONE" ); + //Assert( !"CUtlMemoryPool::Alloc: tried to make new blob with GROW_NONE" ); return NULL; } @@ -246,14 +267,14 @@ void *CUtlMemoryPool::Alloc( size_t amount ) AddNewBlob(); // still failure, error out - if( !m_pHeadOfFreeList ) + if ( !m_pHeadOfFreeList ) { Assert( !"CUtlMemoryPool::Alloc: ran out of memory" ); return NULL; } } m_BlocksAllocated++; - m_PeakAlloc = max(m_PeakAlloc, m_BlocksAllocated); + m_PeakAlloc = MAX(m_PeakAlloc, m_BlocksAllocated); returnBlock = m_pHeadOfFreeList; @@ -272,7 +293,7 @@ void *CUtlMemoryPool::AllocZero( size_t amount ) void *mem = Alloc( amount ); if ( mem ) { - V_memset( mem, 0x00, amount ); + V_memset( mem, 0x00, ( int )amount ); } return mem; } @@ -313,4 +334,14 @@ void CUtlMemoryPool::Free( void *memBlock ) m_pHeadOfFreeList = memBlock; } +int CUtlMemoryPool::Size() const +{ + uint32 size = 0; + + for( CBlob *pCur=m_BlobHead.m_pNext; pCur != &m_BlobHead; pCur=pCur->m_pNext ) + { + size += pCur->m_NumBytes; + } + return size; +} diff --git a/vphysics/physics_virtualmesh.cpp b/vphysics/physics_virtualmesh.cpp index f3c7bd4c..0242478e 100644 --- a/vphysics/physics_virtualmesh.cpp +++ b/vphysics/physics_virtualmesh.cpp @@ -443,7 +443,7 @@ CMeshInstance *CPhysCollideVirtualMesh::BuildLedges() { list.pHull = (byte *)m_pHull; } - + if ( list.triangleCount ) { m_hMemory = g_MeshManager.CreateResource( list ); @@ -532,7 +532,6 @@ CPhysCollide *CreateVirtualMesh( const virtualmeshparams_t ¶ms ) void DestroyVirtualMesh( CPhysCollide *pMesh ) { - FlushFrameLocks(); delete pMesh; } @@ -547,6 +546,7 @@ IVP_SurfaceManager_VirtualMesh::IVP_SurfaceManager_VirtualMesh( CPhysCollideVirt IVP_SurfaceManager_VirtualMesh::~IVP_SurfaceManager_VirtualMesh() { + FlushFrameLocks(); } void IVP_SurfaceManager_VirtualMesh::add_reference_to_ledge(const IVP_Compact_Ledge *ledge) diff --git a/vphysics/vphysics_saverestore.cpp b/vphysics/vphysics_saverestore.cpp index 7cdff13e..dc4b8434 100644 --- a/vphysics/vphysics_saverestore.cpp +++ b/vphysics/vphysics_saverestore.cpp @@ -209,7 +209,6 @@ void CVPhysPtrUtlVectorSaveRestoreOps::Restore( const SaveRestoreFieldInfo_t &fi for ( int i = 0; i < nObjects; i++ ) { void **ppElem = (void**)(&pUtlVector->Element(i)); - pRestore->ReadData( (char *)ppElem, sizeof(void*), 0 ); int iNewVal = s_VPhysPtrMap.Find( *ppElem ); diff --git a/vphysics/vphysics_saverestore.h b/vphysics/vphysics_saverestore.h index c18df61f..8dc5c2d4 100644 --- a/vphysics/vphysics_saverestore.h +++ b/vphysics/vphysics_saverestore.h @@ -69,7 +69,7 @@ public: void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ); private: - typedef CUtlVector VPhysPtrVector; + typedef CUtlVector VPhysPtrVector; }; extern CVPhysPtrUtlVectorSaveRestoreOps g_VPhysPtrUtlVectorSaveRestoreOps; diff --git a/vstdlib/KeyValuesSystem.cpp b/vstdlib/KeyValuesSystem.cpp index 8bd4035f..986ccae0 100644 --- a/vstdlib/KeyValuesSystem.cpp +++ b/vstdlib/KeyValuesSystem.cpp @@ -108,8 +108,8 @@ IKeyValuesSystem *KeyValuesSystem() //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- -CKeyValuesSystem::CKeyValuesSystem() -: m_HashItemMemPool(sizeof(hash_item_t), 64, UTLMEMORYPOOL_GROW_FAST, "CKeyValuesSystem::m_HashItemMemPool") +CKeyValuesSystem::CKeyValuesSystem() +: m_HashItemMemPool(sizeof(hash_item_t), 64, CUtlMemoryPool::GROW_FAST, "CKeyValuesSystem::m_HashItemMemPool") , m_KeyValuesTrackingList(0, 0, MemoryLeakTrackerLessFunc) , m_KeyValueCache( UtlStringLessFunc ) {