2010-07-22 01:46:14 -05:00
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: This header should never be used directly from leaf code!!!
// Instead, just add the file memoverride.cpp into your project and all this
// will automagically be used
//
// $NoKeywords: $
//=============================================================================//
# ifndef TIER0_MEMALLOC_H
# define TIER0_MEMALLOC_H
# ifdef _WIN32
# pragma once
# endif
// These memory debugging switches aren't relevant under Linux builds since memoverride.cpp
// isn't built into Linux projects
# ifndef POSIX
// Define this in release to get memory tracking even in release builds
//#define USE_MEM_DEBUG 1
// Define this in release to get light memory debugging
//#define USE_LIGHT_MEM_DEBUG
// Define this to require -uselmd to turn light memory debugging on
//#define LIGHT_MEM_DEBUG_REQUIRES_CMD_LINE_SWITCH
# endif
# if defined( _MEMTEST )
# ifdef _WIN32
# define USE_MEM_DEBUG 1
# endif
# endif
// Undefine this if using a compiler lacking threadsafe RTTI (like vc6)
# define MEM_DEBUG_CLASSNAME 1
# if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
# include <stddef.h>
# ifdef LINUX
# undef offsetof
# define offsetof(s,m) (size_t)&(((s *)0)->m)
# endif
# include "tier0/mem.h"
struct _CrtMemState ;
# define MEMALLOC_VERSION 1
typedef size_t ( * MemAllocFailHandler_t ) ( size_t ) ;
//-----------------------------------------------------------------------------
// NOTE! This should never be called directly from leaf code
// Just use new,delete,malloc,free etc. They will call into this eventually
//-----------------------------------------------------------------------------
abstract_class IMemAlloc
{
private :
// Release versions
virtual void * Alloc ( size_t nSize ) = 0 ;
public :
virtual void * Realloc ( void * pMem , size_t nSize ) = 0 ;
virtual void Free ( void * pMem ) = 0 ;
virtual void * Expand_NoLongerSupported ( void * pMem , size_t nSize ) = 0 ;
private :
// Debug versions
virtual void * Alloc ( size_t nSize , const char * pFileName , int nLine ) = 0 ;
public :
virtual void * Realloc ( void * pMem , size_t nSize , const char * pFileName , int nLine ) = 0 ;
virtual void Free ( void * pMem , const char * pFileName , int nLine ) = 0 ;
virtual void * Expand_NoLongerSupported ( void * pMem , size_t nSize , const char * pFileName , int nLine ) = 0 ;
inline void * IndirectAlloc ( size_t nSize ) { return Alloc ( nSize ) ; }
inline void * IndirectAlloc ( size_t nSize , const char * pFileName , int nLine ) { return Alloc ( nSize , pFileName , nLine ) ; }
// Returns size of a particular allocation
virtual size_t GetSize ( void * pMem ) = 0 ;
// Force file + line information for an allocation
virtual void PushAllocDbgInfo ( const char * pFileName , int nLine ) = 0 ;
virtual void PopAllocDbgInfo ( ) = 0 ;
// FIXME: Remove when we have our own allocator
// these methods of the Crt debug code is used in our codebase currently
virtual int32 CrtSetBreakAlloc ( int32 lNewBreakAlloc ) = 0 ;
virtual int CrtSetReportMode ( int nReportType , int nReportMode ) = 0 ;
virtual int CrtIsValidHeapPointer ( const void * pMem ) = 0 ;
virtual int CrtIsValidPointer ( const void * pMem , unsigned int size , int access ) = 0 ;
virtual int CrtCheckMemory ( void ) = 0 ;
virtual int CrtSetDbgFlag ( int nNewFlag ) = 0 ;
virtual void CrtMemCheckpoint ( _CrtMemState * pState ) = 0 ;
// FIXME: Make a better stats interface
virtual void DumpStats ( ) = 0 ;
virtual void DumpStatsFileBase ( char const * pchFileBase ) = 0 ;
virtual size_t ComputeMemoryUsedBy ( char const * pchSubStr ) = 0 ;
// FIXME: Remove when we have our own allocator
virtual void * CrtSetReportFile ( int nRptType , void * hFile ) = 0 ;
virtual void * CrtSetReportHook ( void * pfnNewHook ) = 0 ;
virtual int CrtDbgReport ( int nRptType , const char * szFile ,
int nLine , const char * szModule , const char * pMsg ) = 0 ;
virtual int heapchk ( ) = 0 ;
virtual bool IsDebugHeap ( ) = 0 ;
virtual void GetActualDbgInfo ( const char * & pFileName , int & nLine ) = 0 ;
virtual void RegisterAllocation ( const char * pFileName , int nLine , size_t nLogicalSize , size_t nActualSize , unsigned nTime ) = 0 ;
virtual void RegisterDeallocation ( const char * pFileName , int nLine , size_t nLogicalSize , size_t nActualSize , unsigned nTime ) = 0 ;
virtual int GetVersion ( ) = 0 ;
virtual void CompactHeap ( ) = 0 ;
// Function called when malloc fails or memory limits hit to attempt to free up memory (can come in any thread)
virtual MemAllocFailHandler_t SetAllocFailHandler ( MemAllocFailHandler_t pfnMemAllocFailHandler ) = 0 ;
virtual void DumpBlockStats ( void * ) = 0 ;
# if defined( _MEMTEST )
virtual void SetStatsExtraInfo ( const char * pMapName , const char * pComment ) = 0 ;
# endif
// Returns 0 if no failure, otherwise the size_t of the last requested chunk
virtual size_t MemoryAllocFailed ( ) = 0 ;
virtual void CompactIncremental ( ) = 0 ;
virtual void OutOfMemory ( size_t nBytesAttempted = 0 ) = 0 ;
// Region-based allocations
virtual void * RegionAlloc ( int region , size_t nSize ) = 0 ;
virtual void * RegionAlloc ( int region , size_t nSize , const char * pFileName , int nLine ) = 0 ;
// Replacement for ::GlobalMemoryStatus which accounts for unused memory in our system
virtual void GlobalMemoryStatus ( size_t * pUsedMemory , size_t * pFreeMemory ) = 0 ;
} ;
//-----------------------------------------------------------------------------
// Singleton interface
//-----------------------------------------------------------------------------
MEM_INTERFACE IMemAlloc * g_pMemAlloc ;
//-----------------------------------------------------------------------------
# ifdef MEMALLOC_REGIONS
# ifndef MEMALLOC_REGION
# define MEMALLOC_REGION 0
# endif
inline void * MemAlloc_Alloc ( size_t nSize )
{
return g_pMemAlloc - > RegionAlloc ( MEMALLOC_REGION , nSize ) ;
}
inline void * MemAlloc_Alloc ( size_t nSize , const char * pFileName , int nLine )
{
return g_pMemAlloc - > RegionAlloc ( MEMALLOC_REGION , nSize , pFileName , nLine ) ;
}
# else
# undef MEMALLOC_REGION
inline void * MemAlloc_Alloc ( size_t nSize )
{
return g_pMemAlloc - > IndirectAlloc ( nSize ) ;
}
inline void * MemAlloc_Alloc ( size_t nSize , const char * pFileName , int nLine )
{
return g_pMemAlloc - > IndirectAlloc ( nSize , pFileName , nLine ) ;
}
# endif
2015-07-12 19:01:11 -04:00
inline void MemAlloc_Free ( void * ptr )
{
g_pMemAlloc - > Free ( ptr ) ;
}
inline void MemAlloc_Free ( void * ptr , const char * pFileName , int nLine )
{
g_pMemAlloc - > Free ( ptr , pFileName , nLine ) ;
}
2010-07-22 01:46:14 -05:00
//-----------------------------------------------------------------------------
# ifdef MEMALLOC_REGIONS
# else
# endif
inline bool ValueIsPowerOfTwo ( size_t value ) // don't clash with mathlib definition
{
return ( value & ( value - 1 ) ) = = 0 ;
}
inline void * MemAlloc_AllocAlignedUnattributed ( size_t size , size_t align )
{
unsigned char * pAlloc , * pResult ;
if ( ! ValueIsPowerOfTwo ( align ) )
return NULL ;
align = ( align > sizeof ( void * ) ? align : sizeof ( void * ) ) - 1 ;
if ( ( pAlloc = ( unsigned char * ) MemAlloc_Alloc ( sizeof ( void * ) + align + size ) ) = = ( unsigned char * ) NULL )
return NULL ;
pResult = ( unsigned char * ) ( ( size_t ) ( pAlloc + sizeof ( void * ) + align ) & ~ align ) ;
( ( unsigned char * * ) ( pResult ) ) [ - 1 ] = pAlloc ;
return ( void * ) pResult ;
}
inline void * MemAlloc_AllocAlignedFileLine ( size_t size , size_t align , const char * pszFile , int nLine )
{
unsigned char * pAlloc , * pResult ;
if ( ! ValueIsPowerOfTwo ( align ) )
return NULL ;
align = ( align > sizeof ( void * ) ? align : sizeof ( void * ) ) - 1 ;
if ( ( pAlloc = ( unsigned char * ) MemAlloc_Alloc ( sizeof ( void * ) + align + size , pszFile , nLine ) ) = = ( unsigned char * ) NULL )
return NULL ;
pResult = ( unsigned char * ) ( ( size_t ) ( pAlloc + sizeof ( void * ) + align ) & ~ align ) ;
( ( unsigned char * * ) ( pResult ) ) [ - 1 ] = pAlloc ;
return ( void * ) pResult ;
}
# ifdef USE_MEM_DEBUG
# define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, __FILE__, __LINE__ )
# elif defined(USE_LIGHT_MEM_DEBUG)
extern const char * g_pszModule ;
# define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedFileLine( s, a, g_pszModule, 0 )
# else
# define MemAlloc_AllocAligned( s, a ) MemAlloc_AllocAlignedUnattributed( s, a )
# endif
inline void * MemAlloc_ReallocAligned ( void * ptr , size_t size , size_t align )
{
if ( ! ValueIsPowerOfTwo ( align ) )
return NULL ;
// Don't change alignment between allocation + reallocation.
if ( ( ( size_t ) ptr & ( align - 1 ) ) ! = 0 )
return NULL ;
if ( ! ptr )
return MemAlloc_AllocAligned ( size , align ) ;
void * pAlloc , * pResult ;
// Figure out the actual allocation point
pAlloc = ptr ;
pAlloc = ( void * ) ( ( ( size_t ) pAlloc & ~ ( sizeof ( void * ) - 1 ) ) - sizeof ( void * ) ) ;
pAlloc = * ( ( void * * ) pAlloc ) ;
// See if we have enough space
size_t nOffset = ( size_t ) ptr - ( size_t ) pAlloc ;
size_t nOldSize = g_pMemAlloc - > GetSize ( pAlloc ) ;
if ( nOldSize > = size + nOffset )
return ptr ;
pResult = MemAlloc_AllocAligned ( size , align ) ;
memcpy ( pResult , ptr , nOldSize - nOffset ) ;
g_pMemAlloc - > Free ( pAlloc ) ;
return pResult ;
}
inline void MemAlloc_FreeAligned ( void * pMemBlock )
{
void * pAlloc ;
if ( pMemBlock = = NULL )
return ;
pAlloc = pMemBlock ;
// pAlloc points to the pointer to starting of the memory block
pAlloc = ( void * ) ( ( ( size_t ) pAlloc & ~ ( sizeof ( void * ) - 1 ) ) - sizeof ( void * ) ) ;
// pAlloc is the pointer to the start of memory block
pAlloc = * ( ( void * * ) pAlloc ) ;
g_pMemAlloc - > Free ( pAlloc ) ;
}
inline void MemAlloc_FreeAligned ( void * pMemBlock , const char * pszFile , int nLine )
{
void * pAlloc ;
if ( pMemBlock = = NULL )
return ;
pAlloc = pMemBlock ;
// pAlloc points to the pointer to starting of the memory block
pAlloc = ( void * ) ( ( ( size_t ) pAlloc & ~ ( sizeof ( void * ) - 1 ) ) - sizeof ( void * ) ) ;
// pAlloc is the pointer to the start of memory block
pAlloc = * ( ( void * * ) pAlloc ) ;
g_pMemAlloc - > Free ( pAlloc , pszFile , nLine ) ;
}
inline size_t MemAlloc_GetSizeAligned ( void * pMemBlock )
{
void * pAlloc ;
if ( pMemBlock = = NULL )
return 0 ;
pAlloc = pMemBlock ;
// pAlloc points to the pointer to starting of the memory block
pAlloc = ( void * ) ( ( ( size_t ) pAlloc & ~ ( sizeof ( void * ) - 1 ) ) - sizeof ( void * ) ) ;
// pAlloc is the pointer to the start of memory block
pAlloc = * ( ( void * * ) pAlloc ) ;
return g_pMemAlloc - > GetSize ( pAlloc ) - ( ( byte * ) pMemBlock - ( byte * ) pAlloc ) ;
}
struct aligned_tmp_t
{
// empty base class
} ;
// template here to allow adding alignment at levels of hierarchy that aren't the base
template < int bytesAlignment = 16 , class T = aligned_tmp_t >
class CAlignedNewDelete : public T
{
public :
void * operator new ( size_t nSize )
{
return MemAlloc_AllocAligned ( nSize , bytesAlignment ) ;
}
void * operator new ( size_t nSize , int nBlockUse , const char * pFileName , int nLine )
{
return MemAlloc_AllocAlignedFileLine ( nSize , bytesAlignment , pFileName , nLine ) ;
}
void operator delete ( void * pData )
{
if ( pData )
{
MemAlloc_FreeAligned ( pData ) ;
}
}
void operator delete ( void * pData , int nBlockUse , const char * pFileName , int nLine )
{
if ( pData )
{
MemAlloc_FreeAligned ( pData , pFileName , nLine ) ;
}
}
} ;
//-----------------------------------------------------------------------------
# if (defined(_DEBUG) || defined(USE_MEM_DEBUG))
# define MEM_ALLOC_CREDIT_(tag) CMemAllocAttributeAlloction memAllocAttributeAlloction( tag, __LINE__ )
# define MemAlloc_PushAllocDbgInfo( pszFile, line ) g_pMemAlloc->PushAllocDbgInfo( pszFile, line )
# define MemAlloc_PopAllocDbgInfo() g_pMemAlloc->PopAllocDbgInfo()
# define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime )
# define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) g_pMemAlloc->RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime )
# else
# define MEM_ALLOC_CREDIT_(tag) ((void)0)
# define MemAlloc_PushAllocDbgInfo( pszFile, line ) ((void)0)
# define MemAlloc_PopAllocDbgInfo() ((void)0)
# define MemAlloc_RegisterAllocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
# define MemAlloc_RegisterDeallocation( pFileName, nLine, nLogicalSize, nActualSize, nTime ) ((void)0)
# endif
//-----------------------------------------------------------------------------
class CMemAllocAttributeAlloction
{
public :
CMemAllocAttributeAlloction ( const char * pszFile , int line )
{
MemAlloc_PushAllocDbgInfo ( pszFile , line ) ;
}
~ CMemAllocAttributeAlloction ( )
{
MemAlloc_PopAllocDbgInfo ( ) ;
}
} ;
# define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__)
//-----------------------------------------------------------------------------
# if defined(MSVC) && ( defined(_DEBUG) || defined(USE_MEM_DEBUG) )
# pragma warning(disable:4290)
# pragma warning(push)
# include <typeinfo.h>
// MEM_DEBUG_CLASSNAME is opt-in.
// Note: typeid().name() is not threadsafe, so if the project needs to access it in multiple threads
// simultaneously, it'll need a mutex.
# if defined(_CPPRTTI) && defined(MEM_DEBUG_CLASSNAME)
template < typename T > const char * MemAllocClassName ( T * p )
{
static const char * pszName = typeid ( * p ) . name ( ) ; // @TODO: support having debug heap ignore certain allocations, and ignore memory allocated here [5/7/2009 tom]
return pszName ;
}
# define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( MemAllocClassName( this ) )
# define MEM_ALLOC_CLASSNAME(type) (typeid((type*)(0)).name())
# else
# define MEM_ALLOC_CREDIT_CLASS() MEM_ALLOC_CREDIT_( __FILE__ )
# define MEM_ALLOC_CLASSNAME(type) (__FILE__)
# endif
// MEM_ALLOC_CREDIT_FUNCTION is used when no this pointer is available ( inside 'new' overloads, for example )
# ifdef _MSC_VER
# define MEM_ALLOC_CREDIT_FUNCTION() MEM_ALLOC_CREDIT_( __FUNCTION__ )
# else
# define MEM_ALLOC_CREDIT_FUNCTION() (__FILE__)
# endif
# pragma warning(pop)
# else
# define MEM_ALLOC_CREDIT_CLASS()
# define MEM_ALLOC_CLASSNAME(type) NULL
# define MEM_ALLOC_CREDIT_FUNCTION()
# endif
//-----------------------------------------------------------------------------
# if (defined(_DEBUG) || defined(USE_MEM_DEBUG))
struct MemAllocFileLine_t
{
const char * pszFile ;
int line ;
} ;
# define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag ) \
static CUtlMap < void * , MemAllocFileLine_t , int > s_ # # tag # # Allocs ( DefLessFunc ( void * ) ) ; \
CUtlMap < void * , MemAllocFileLine_t , int > * g_p # # tag # # Allocs = & s_ # # tag # # Allocs ; \
const char * g_psz # # tag # # Alloc = strcpy ( ( char * ) MemAlloc_Alloc ( strlen ( # tag " Alloc " ) + 1 , " intentional leak " , 0 ) , # tag " Alloc " ) ;
# define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag ) \
extern CUtlMap < void * , MemAllocFileLine_t , int > * g_p # # tag # # Allocs ; \
extern const char * g_psz # # tag # # Alloc ;
# define MemAlloc_RegisterExternalAllocation( tag, p, size ) \
if ( ! p ) \
; \
else \
{ \
MemAllocFileLine_t fileLine = { g_psz # # tag # # Alloc , 0 } ; \
g_pMemAlloc - > GetActualDbgInfo ( fileLine . pszFile , fileLine . line ) ; \
if ( fileLine . pszFile ! = g_psz # # tag # # Alloc ) \
{ \
g_p # # tag # # Allocs - > Insert ( p , fileLine ) ; \
} \
\
MemAlloc_RegisterAllocation ( fileLine . pszFile , fileLine . line , size , size , 0 ) ; \
}
# define MemAlloc_RegisterExternalDeallocation( tag, p, size ) \
if ( ! p ) \
; \
else \
{ \
MemAllocFileLine_t fileLine = { g_psz # # tag # # Alloc , 0 } ; \
CUtlMap < void * , MemAllocFileLine_t , int > : : IndexType_t iRecordedFileLine = g_p # # tag # # Allocs - > Find ( p ) ; \
if ( iRecordedFileLine ! = g_p # # tag # # Allocs - > InvalidIndex ( ) ) \
{ \
fileLine = ( * g_p # # tag # # Allocs ) [ iRecordedFileLine ] ; \
g_p # # tag # # Allocs - > RemoveAt ( iRecordedFileLine ) ; \
} \
\
MemAlloc_RegisterDeallocation ( fileLine . pszFile , fileLine . line , size , size , 0 ) ; \
}
# else
# define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
# define MEMALLOC_DECLARE_EXTERNAL_TRACKING( tag )
# define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
# define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
# endif
//-----------------------------------------------------------------------------
# endif // !STEAM && !NO_MALLOC_OVERRIDE
//-----------------------------------------------------------------------------
# if !defined(STEAM) && defined(NO_MALLOC_OVERRIDE)
# include <malloc.h>
# define MEM_ALLOC_CREDIT_(tag) ((void)0)
# define MEM_ALLOC_CREDIT() MEM_ALLOC_CREDIT_(__FILE__)
# define MEM_ALLOC_CREDIT_CLASS()
# define MEM_ALLOC_CLASSNAME(type) NULL
# define MemAlloc_PushAllocDbgInfo( pszFile, line )
# define MemAlloc_PopAllocDbgInfo()
# define MEMALLOC_DEFINE_EXTERNAL_TRACKING( tag )
# define MemAlloc_RegisterExternalAllocation( tag, p, size ) ((void)0)
# define MemAlloc_RegisterExternalDeallocation( tag, p, size ) ((void)0)
inline void * MemAlloc_AllocAligned ( size_t size , size_t align )
{
return ( void * ) _aligned_malloc ( size , align ) ;
}
inline void * MemAlloc_AllocAligned ( size_t size , size_t align , const char * pszFile , int nLine )
{
pszFile = pszFile ;
nLine = nLine ;
return ( void * ) _aligned_malloc ( size , align ) ;
}
inline void MemAlloc_FreeAligned ( void * pMemBlock )
{
_aligned_free ( pMemBlock ) ;
}
inline void MemAlloc_FreeAligned ( void * pMemBlock , const char * pszFile , int nLine )
{
pszFile = pszFile ;
nLine = nLine ;
_aligned_free ( pMemBlock ) ;
}
# endif // !STEAM && NO_MALLOC_OVERRIDE
//-----------------------------------------------------------------------------
// linux memory tracking via hooks.
# ifdef _POSIX
PLATFORM_INTERFACE void MemoryLogMessage ( char const * s ) ; // throw a message into the memory log
PLATFORM_INTERFACE void EnableMemoryLogging ( bool bOnOff ) ;
PLATFORM_INTERFACE void DumpMemoryLog ( int nThresh ) ;
PLATFORM_INTERFACE void DumpMemorySummary ( void ) ;
PLATFORM_INTERFACE void SetMemoryMark ( void ) ;
PLATFORM_INTERFACE void DumpChangedMemory ( int nThresh ) ;
// ApproximateProcessMemoryUsage returns the approximate memory footprint of this process.
PLATFORM_INTERFACE size_t ApproximateProcessMemoryUsage ( void ) ;
# else
inline void MemoryLogMessage ( char const * )
{
}
inline void EnableMemoryLogging ( bool )
{
}
inline void DumpMemoryLog ( int )
{
}
inline void DumpMemorySummary ( void )
{
}
inline void SetMemoryMark ( void )
{
}
inline void DumpChangedMemory ( int )
{
}
inline size_t ApproximateProcessMemoryUsage ( void )
{
return 0 ;
}
# endif
# endif /* TIER0_MEMALLOC_H */