csgo-2018-source/tier0/memvirt.cpp
2021-07-24 21:11:47 -07:00

666 lines
20 KiB
C++

//===== Copyright © 2010, Valve Corporation, All rights reserved. ======//
//
// Purpose: Virtual memory sections management!
//
// $NoKeywords: $
//===========================================================================//
#include "pch_tier0.h"
#if !defined(STEAM) && !defined(NO_MALLOC_OVERRIDE)
//#include <malloc.h>
#include <string.h>
#include "tier0/dbg.h"
#include "tier0/stacktools.h"
#include "tier0/memalloc.h"
#include "tier0/memvirt.h"
#include "tier0/fasttimer.h"
#include "mem_helpers.h"
#ifdef PLATFORM_WINDOWS_PC
#undef WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <crtdbg.h>
#endif
#ifdef OSX
#include <malloc/malloc.h>
#include <stdlib.h>
#endif
#include <map>
#include <set>
#include <limits.h>
#include "tier0/threadtools.h"
#ifdef _X360
#include "xbox/xbox_console.h"
#endif
#ifdef _PS3
#include "tls_ps3.h"
#include "memoverride_ps3.h"
#include "sys/memory.h"
#include "sys/mempool.h"
#include "sys/process.h"
#include "sys/vm.h"
#endif
CInterlockedInt VmmMsgFlag = 0; // Prevents re-entrancy within VmmMsg (printf allocates a large buffer!)
#ifdef _DEBUG
#ifdef _PS3 // _DEBUG
#define VmmMsg( mutex, ... ) ( (VmmMsgFlag|mutex.GetOwnerId()) ? 0 : ( ++VmmMsgFlag, Msg( __VA_ARGS__ ), VmmMsgFlag-- ) )
#else
#define VmmMsg( mutex, ... ) ( (VmmMsgFlag|mutex.GetOwnerId()) ? 0 : ( ++VmmMsgFlag, DevMsg( __VA_ARGS__ ), VmmMsgFlag-- ) )
#endif
#else
#define VmmMsg( mutex, ... ) ((void)0)
#endif
#if 0
#define TRACE_CALL( ... ) do { FILE *fPs3Trace = fopen( "/app_home/tracevmm.txt", "a+" ); if( fPs3Trace ) { fprintf( fPs3Trace, __VA_ARGS__ ); fclose( fPs3Trace ); } } while( 0 )
#else
#define TRACE_CALL( ... ) ((void)0)
#endif
#ifdef _PS3
#define VIRTUAL_MEMORY_MANAGER_SUPPORTED
#define VMM_SYSTEM_PAGE_POLICY SYS_MEMORY_PAGE_SIZE_64K
#define VMM_SYSTEM_PAGE_ALLOCFLAGS SYS_MEMORY_GRANULARITY_64K
#define VMM_POLICY_SYS_VM 0 // sys_vm_* system is really buggy and console sometimes hardlocks or crashes in OS
#define VMM_POLICY_SYS_MMAPPER 1 // sys_mmapper_* seems fairly stable
#define VMM_POLICY_SYS_VM_NO_RETURN 1 // looks like returning memory under sys_vm_* is the main reason for hardlocks
#if !(VMM_POLICY_SYS_VM) == !(VMM_POLICY_SYS_MMAPPER)
#error
#endif
class CVirtualMemoryManager
{
public:
CVirtualMemoryManager();
~CVirtualMemoryManager() { Shutdown(); }
void Shutdown();
IVirtualMemorySection * AllocateVirtualMemorySection( size_t numMaxBytes );
IVirtualMemorySection * NewSection( byte *pBase, size_t numMaxBytes );
IVirtualMemorySection * GetMemorySectionForAddress( void *pAddress );
void GetStats( size_t &nReserved, size_t &nReservedMax, size_t &nCommitted, size_t &nCommittedMax );
public:
byte *m_pBase; // base address of the virtual address space
size_t m_nPhysicalSize; // physical memory committed
size_t m_nPhysicalSizeMax; // physical memory committed (max since startup)
size_t m_nVirtualSize; // virtual memory reserved
size_t m_nVirtualSizeMax; // virtual memory reserved (max since startup)
#if VMM_POLICY_SYS_VM
size_t m_nSparePhysicalSize; // physical memory that has been decommitted, but hasn't been returned
#endif
#if VMM_POLICY_SYS_MMAPPER
sys_memory_t m_sysMemPages[ VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE ];
#endif
IVirtualMemorySection *m_uiVirtualMap[ VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE ]; // map of pages to sections
uint32 m_uiCommitMask[ VMM_VIRTUAL_SIZE / ( VMM_PAGE_SIZE * 32 ) ]; // mask of committed pages
inline bool CommitTest( int iPage ) const
{
const uint32 mask = 1u << ( iPage % 32 ), &word = m_uiCommitMask[ iPage / 32 ];
return !!( word & mask );
}
inline void CommitSet( int iPage, bool bSet )
{
uint32 mask = 1u << ( iPage % 32 ), &word = m_uiCommitMask[ iPage / 32 ];
word = ( word & ~mask ) | ( bSet ? mask : 0 );
}
inline size_t CountReservedPages()
{
size_t uResult = 0;
for ( int k = 0; k < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ k )
uResult += m_uiVirtualMap[k] ? 1 : 0;
return uResult;
}
inline size_t CountCommittedPages() const
{
size_t uResult = 0;
for ( int k = 0; k < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ k )
uResult += CommitTest(k) ? 1 : 0;
return uResult;
}
public:
bool CommitPage( byte *pbAddress );
bool DecommitPage( byte *pbAddress );
public:
CThreadFastMutex m_Mutex;
};
static CVirtualMemoryManager& GetVirtualMemoryManager()
{
static CVirtualMemoryManager s_VirtualMemoryManager;
return s_VirtualMemoryManager;
}
CVirtualMemoryManager::CVirtualMemoryManager() :
m_pBase( NULL ),
#if VMM_POLICY_SYS_VM
m_nSparePhysicalSize( 0 ),
#endif
m_nPhysicalSize( 0 ),
m_nPhysicalSizeMax( 0 ),
m_nVirtualSize( 0 ),
m_nVirtualSizeMax( 0 )
{
memset( m_uiVirtualMap, 0, sizeof( m_uiVirtualMap ) );
memset( m_uiCommitMask, 0, sizeof( m_uiCommitMask ) );
#if VMM_POLICY_SYS_VM
TRACE_CALL( "sys_vm_memory_map( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X ) ... ",
VMM_VIRTUAL_SIZE,
VMM_PAGE_SIZE,
SYS_MEMORY_CONTAINER_ID_INVALID,
VMM_SYSTEM_PAGE_POLICY,
SYS_VM_POLICY_AUTO_RECOMMENDED,
reinterpret_cast<sys_addr_t*>( &m_pBase ) );
int retval = sys_vm_memory_map(
VMM_VIRTUAL_SIZE,
VMM_PAGE_SIZE,
SYS_MEMORY_CONTAINER_ID_INVALID,
VMM_SYSTEM_PAGE_POLICY,
SYS_VM_POLICY_AUTO_RECOMMENDED,
reinterpret_cast<sys_addr_t*>( &m_pBase ) );
TRACE_CALL( "ret = 0x%08X, base = 0x%08X\n",
retval, m_pBase );
if ( retval < CELL_OK || !m_pBase )
{
Error( "sys_vm_memory_map failed( size=%dKB, page=%dKB ), error=0x%08X\n", VMM_VIRTUAL_SIZE / VMM_KB, VMM_PAGE_SIZE / VMM_KB, retval );
Assert( 0 );
m_pBase = NULL;
return;
}
#endif
#if VMM_POLICY_SYS_MMAPPER
memset( m_sysMemPages, 0, sizeof( m_sysMemPages ) );
TRACE_CALL( "sys_mmapper_allocate_address( 0x%08X, 0x%08X, 0x%08X, 0x%08X ) ... ",
VMM_VIRTUAL_SIZE,
VMM_SYSTEM_PAGE_POLICY,
VMM_VIRTUAL_SIZE,
reinterpret_cast<sys_addr_t*>( &m_pBase ) );
int retval = sys_mmapper_allocate_address(
VMM_VIRTUAL_SIZE,
VMM_SYSTEM_PAGE_POLICY,
VMM_VIRTUAL_SIZE,
reinterpret_cast<sys_addr_t*>( &m_pBase ) );
TRACE_CALL( "ret = 0x%08X, base = 0x%08X\n",
retval, m_pBase );
if ( retval < CELL_OK || !m_pBase )
{
Error( "sys_mmapper_allocate_address failed( size=%dKB, page=%dKB ), error=0x%08X\n", VMM_VIRTUAL_SIZE / VMM_KB, VMM_PAGE_SIZE / VMM_KB, retval );
Assert( 0 );
m_pBase = NULL;
return;
}
#endif
VmmMsg( m_Mutex, "Virtual Memory Manager: reserved %uKB block at address 0x%08X.\n", VMM_VIRTUAL_SIZE / VMM_KB, m_pBase );
}
void CVirtualMemoryManager::Shutdown()
{
if ( !m_pBase )
return;
if ( m_nPhysicalSize )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: shutting down with %uKB allocated!\n", m_nPhysicalSize / VMM_KB );
}
#if VMM_POLICY_SYS_VM
TRACE_CALL( "sys_vm_unmap( 0x%08X ) ... ", (sys_addr_t) m_pBase );
int retval = sys_vm_unmap( (sys_addr_t) m_pBase );
TRACE_CALL( "ret = 0x%08X\n", retval );
#endif
#if VMM_POLICY_SYS_MMAPPER
TRACE_CALL( "sys_mmapper_free_address( 0x%08X ) ... ", (sys_addr_t) m_pBase );
int retval = sys_mmapper_free_address( (sys_addr_t) m_pBase );
TRACE_CALL( "ret = 0x%08X\n", retval );
#endif
VmmMsg( m_Mutex, "Virtual Memory Manager: unmapped %uKB block at address 0x%08X (result=0x%08X).\n", VMM_VIRTUAL_SIZE / VMM_KB, m_pBase, retval );
m_pBase = NULL;
}
IVirtualMemorySection * CVirtualMemoryManager::GetMemorySectionForAddress( void *pAddress )
{
Assert( ( pAddress >= m_pBase ) && ( pAddress < ( m_pBase + VMM_VIRTUAL_SIZE ) ) );
int iPage = ( (byte*)pAddress - m_pBase ) / VMM_PAGE_SIZE;
return m_uiVirtualMap[ iPage ];
}
IVirtualMemorySection * CVirtualMemoryManager::AllocateVirtualMemorySection( size_t numMaxBytes )
{
Assert( m_pBase );
if ( !m_pBase )
return NULL;
// Find the smallest free block with size >= numMaxBytes
IVirtualMemorySection *pResult = NULL;
int iGoodPage = -1;
int iGoodSize = 0;
size_t numPages = numMaxBytes / VMM_PAGE_SIZE;
if ( !numPages )
return NULL;
{
AUTO_LOCK( m_Mutex );
// TODO: fill the address range with reserved/free sections (so we iterate 50 sections rather than 8000 pages!)
for ( int iTryPage = 0; iTryPage < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ iTryPage )
{
if ( m_uiVirtualMap[ iTryPage ] )
continue; // page is taken
int iTryPageStart = iTryPage;
int iTryPageStride = 1;
for ( ++ iTryPage; iTryPage < VMM_VIRTUAL_SIZE / VMM_PAGE_SIZE; ++ iTryPage, ++ iTryPageStride )
if ( m_uiVirtualMap[ iTryPage ] )
break;
if ( iTryPageStride < numPages )
continue;
if ( ( iGoodPage < 0 ) || ( iTryPageStride < iGoodSize ) )
{
iGoodPage = iTryPageStart;
iGoodSize = iTryPageStride;
}
}
if ( iGoodPage >= 0 )
{
byte *pbAddress = m_pBase + iGoodPage * VMM_PAGE_SIZE;
pResult = NewSection( pbAddress, numMaxBytes );
m_nVirtualSize += numPages*VMM_PAGE_SIZE;
m_nVirtualSizeMax = MAX( m_nVirtualSize, m_nVirtualSizeMax );
// Mark pages used
for ( int k = 0; k < numPages; ++ k )
m_uiVirtualMap[ iGoodPage + k ] = pResult;
}
}
if ( pResult )
{
// NOTE: don't spew while the mutex is held!
VmmMsg( m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: new reservation %uKB @ 0x%08X\n",
CountReservedPages()*VMM_PAGE_SIZE / VMM_KB,
CountCommittedPages()*VMM_PAGE_SIZE / VMM_KB,
numMaxBytes / VMM_KB, pResult->GetBaseAddress() );
return pResult;
}
Error( "CVirtualMemoryManager::AllocateVirtualMemorySection has no memory for %u bytes!\n", numMaxBytes );
Assert( 0 );
return NULL;
}
bool CVirtualMemoryManager::CommitPage( byte *pbAddress )
{
Assert( m_pBase );
int iPage = ( pbAddress - m_pBase ) / VMM_PAGE_SIZE;
if ( CommitTest( iPage ) )
return true;
CommitSet( iPage, true );
#if VMM_POLICY_SYS_VM
if ( m_nPhysicalSize )
{
if ( m_nSparePhysicalSize > 0 )
{
m_nSparePhysicalSize -= VMM_PAGE_SIZE;
}
else
{
TRACE_CALL( "sys_vm_append_memory( 0x%08X, 0x%08X ) ... ", (sys_addr_t) m_pBase, VMM_PAGE_SIZE );
int retval = sys_vm_append_memory( (sys_addr_t) m_pBase, VMM_PAGE_SIZE );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_vm_append_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
}
}
m_nPhysicalSize += VMM_PAGE_SIZE;
m_nPhysicalSizeMax = MAX( m_nPhysicalSize, m_nPhysicalSizeMax );
TRACE_CALL( "sys_vm_touch( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
int retval = sys_vm_touch( (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_vm_touch failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
#endif
#if VMM_POLICY_SYS_MMAPPER
TRACE_CALL( "sys_mmapper_allocate_memory( 0x%08X, 0x%08X, page=%d ) ... ", VMM_PAGE_SIZE, VMM_SYSTEM_PAGE_ALLOCFLAGS, iPage );
int retval = sys_mmapper_allocate_memory( VMM_PAGE_SIZE, VMM_SYSTEM_PAGE_ALLOCFLAGS, &m_sysMemPages[iPage] );
TRACE_CALL( "ret = 0x%08X, mem = 0x%08X\n", retval, m_sysMemPages[iPage] );
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_mmapper_allocate_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
m_nPhysicalSize += VMM_PAGE_SIZE;
m_nPhysicalSizeMax = MAX( m_nPhysicalSize, m_nPhysicalSizeMax );
TRACE_CALL( "sys_mmapper_map_memory( 0x%08X, 0x%08X, 0x%08X, page=%d ) ... ", (sys_addr_t) pbAddress, m_sysMemPages[iPage], SYS_MEMORY_PROT_READ_WRITE, iPage );
retval = sys_mmapper_map_memory( (sys_addr_t) pbAddress, m_sysMemPages[iPage], SYS_MEMORY_PROT_READ_WRITE );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: CommitPage: sys_mmapper_map_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
#endif
return true;
}
bool CVirtualMemoryManager::DecommitPage( byte *pbAddress )
{
Assert( m_pBase );
int iPage = ( pbAddress - m_pBase ) / VMM_PAGE_SIZE;
if ( !CommitTest( iPage ) )
return false;
CommitSet( iPage, false );
#if VMM_POLICY_SYS_VM
TRACE_CALL( "sys_vm_invalidate( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
int retval = sys_vm_invalidate( (sys_addr_t) pbAddress, VMM_PAGE_SIZE );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: DecommitPage: sys_vm_invalidate failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
m_nPhysicalSize -= VMM_PAGE_SIZE;
#if VMM_POLICY_SYS_VM_NO_RETURN
m_nSparePhysicalSize += VMM_PAGE_SIZE;
return false;
#else
return m_nPhysicalSize >= VMM_PAGE_SIZE;
#endif
#endif
#if VMM_POLICY_SYS_MMAPPER
TRACE_CALL( "sys_mmapper_unmap_memory( 0x%08X, 0x%08X, page=%d ) ... ", (sys_addr_t) pbAddress, m_sysMemPages[iPage], iPage );
int retval = sys_mmapper_unmap_memory( (sys_addr_t) pbAddress, &m_sysMemPages[iPage] );
TRACE_CALL( "ret = 0x%08X, mem = 0x%08X\n", retval, m_sysMemPages[iPage] );
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: DecommitPage: sys_mmapper_unmap_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
TRACE_CALL( "sys_mmapper_free_memory( 0x%08X, page=%d ) ... ", m_sysMemPages[iPage], iPage );
retval = sys_mmapper_free_memory( m_sysMemPages[iPage] );
TRACE_CALL( "ret = 0x%08X\n", retval );
m_sysMemPages[iPage] = 0;
if ( retval < CELL_OK )
{
VmmMsg( m_Mutex, "Virtual Memory Manager: DecommitPage: sys_mmapper_free_memory failed (result=0x%08X), %uKB committed so far.\n", retval, m_nPhysicalSize / VMM_KB );
return false;
}
m_nPhysicalSize -= VMM_PAGE_SIZE;
return true;
#endif
}
void CVirtualMemoryManager::GetStats( size_t &nReserved, size_t &nReservedMax, size_t &nCommitted, size_t &nCommittedMax )
{
AUTO_LOCK( m_Mutex );
nReserved = m_nVirtualSize;
nReservedMax = m_nVirtualSizeMax;
nCommitted = m_nPhysicalSize;
nCommittedMax = m_nPhysicalSizeMax;
}
class CVirtualMemorySectionImpl : public IVirtualMemorySection
{
public:
CVirtualMemorySectionImpl( byte *pbAddress, size_t numMaxBytes ) :
m_pBase( pbAddress ),
m_numMaxBytes( numMaxBytes ),
m_numPhysical( 0 )
{
}
// Information about memory section
virtual void * GetBaseAddress() { return m_pBase; }
virtual size_t GetPageSize() { return VMM_PAGE_SIZE; }
virtual size_t GetTotalSize() { return m_numMaxBytes; }
// Functions to manage physical memory mapped to virtual memory
virtual bool CommitPages( void *pvBase, size_t numBytes );
virtual void DecommitPages( void *pvBase, size_t numBytes );
bool CommitPages_Inner( void *pvBase, size_t numBytes );
// Release the physical memory and associated virtual address space
virtual void Release();
byte *m_pBase;
size_t m_numMaxBytes;
size_t m_numPhysical;
};
bool CVirtualMemorySectionImpl::CommitPages_Inner( void *pvBase, size_t numBytes )
{
Assert( pvBase >= m_pBase );
Assert( ( (byte*)pvBase ) + numBytes <= m_pBase + m_numMaxBytes );
{
AUTO_LOCK( GetVirtualMemoryManager().m_Mutex );
int startPage = ( ( (byte*)pvBase ) - m_pBase ) / VMM_PAGE_SIZE;
int endPage = ( ( (byte*)pvBase ) + numBytes + ( VMM_PAGE_SIZE - 1 ) - m_pBase ) / VMM_PAGE_SIZE;
for ( int k = startPage; k < endPage; k++ )
{
if ( !GetVirtualMemoryManager().CommitPage( m_pBase + k * VMM_PAGE_SIZE ) )
{
// Failure! Decommit the pages we have committed so far:
for ( k = k - 1; k >= startPage; k-- )
{
GetVirtualMemoryManager().DecommitPage( m_pBase + k * VMM_PAGE_SIZE );
}
return false;
}
}
#if VMM_POLICY_SYS_VM
TRACE_CALL( "sys_vm_sync( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pvBase, numBytes );
int retval = sys_vm_sync( (sys_addr_t) pvBase, numBytes );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager: CommitPages: sys_vm_sync failed (result=0x%08X).\n", retval );
return false;
}
#endif
}
// NOTE: we don't spew while the mutex is held!
VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: committed %uKB @ 0x%08X\n",
GetVirtualMemoryManager().CountReservedPages() * VMM_PAGE_SIZE / VMM_KB,
GetVirtualMemoryManager().CountCommittedPages() * VMM_PAGE_SIZE / VMM_KB,
numBytes / VMM_KB, pvBase );
return true;
}
bool CVirtualMemorySectionImpl::CommitPages( void *pvBase, size_t numBytes )
{
if ( CommitPages_Inner( pvBase, numBytes ) )
return true;
// On failure, compact the heap and try one last time:
Msg( "\n\nVirtual Memory Manager: COMMIT FAILED! (%d) Last-ditch effort: compacting the heap and re-trying...\n", numBytes );
g_pMemAllocInternalPS3->CompactHeap();
bool success = CommitPages_Inner( pvBase, numBytes );
if ( !success )
{
Msg( "Virtual Memory Manager: COMMIT FAILED! (%d) Fatal error.\n\n\n", numBytes );
g_pMemAllocInternalPS3->OutOfMemory( numBytes );
}
Msg("\n\n");
return success;
}
void CVirtualMemorySectionImpl::DecommitPages( void *pvBase, size_t numBytes )
{
Assert( pvBase >= m_pBase );
Assert( ( (byte*)pvBase ) + numBytes <= m_pBase + m_numMaxBytes );
{
AUTO_LOCK( GetVirtualMemoryManager().m_Mutex );
int numPagesDecommitted = 0;
for ( int k = ( ( (byte*)pvBase ) - m_pBase ) / VMM_PAGE_SIZE;
m_pBase + k * VMM_PAGE_SIZE < ( (byte*)pvBase ) + numBytes; ++ k )
{
numPagesDecommitted += !!GetVirtualMemoryManager().DecommitPage( m_pBase + k * VMM_PAGE_SIZE );
}
#if VMM_POLICY_SYS_VM
TRACE_CALL( "sys_vm_sync( 0x%08X, 0x%08X ) ... ", (sys_addr_t) pvBase, numBytes );
int retval = sys_vm_sync( (sys_addr_t) pvBase, numBytes );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager: DecommitPages: sys_vm_sync failed (result=0x%08X).\n", retval );
}
if ( numPagesDecommitted > 0 )
{
TRACE_CALL( "sys_vm_return_memory( 0x%08X, 0x%08X ) ... ", (sys_addr_t) GetVirtualMemoryManager().m_pBase, numPagesDecommitted * VMM_PAGE_SIZE );
retval = sys_vm_return_memory( (sys_addr_t) GetVirtualMemoryManager().m_pBase, numPagesDecommitted * VMM_PAGE_SIZE );
TRACE_CALL( "ret = 0x%08X\n", retval );
if ( retval < CELL_OK )
{
VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager: DecommitPages: sys_vm_return_memory failed (result=0x%08X).\n", retval );
}
}
#endif
}
// NOTE: we don't spew while the mutex is held!
VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: decommitted %uKB @ 0x%08X\n",
GetVirtualMemoryManager().CountReservedPages() * VMM_PAGE_SIZE / VMM_KB,
GetVirtualMemoryManager().CountCommittedPages() * VMM_PAGE_SIZE / VMM_KB,
numBytes / VMM_KB, pvBase );
}
void CVirtualMemorySectionImpl::Release()
{
DecommitPages( m_pBase, m_numMaxBytes );
{
AUTO_LOCK( GetVirtualMemoryManager().m_Mutex );
int iPageStart = ( m_pBase - GetVirtualMemoryManager().m_pBase ) / VMM_PAGE_SIZE;
for ( int k = 0; m_pBase + k * VMM_PAGE_SIZE < m_pBase + m_numMaxBytes; ++ k )
{
Assert( GetVirtualMemoryManager().m_uiVirtualMap[ iPageStart + k ] == this );
GetVirtualMemoryManager().m_uiVirtualMap[ iPageStart + k ] = NULL;
GetVirtualMemoryManager().m_nVirtualSize -= VMM_PAGE_SIZE;
}
}
// NOTE: we don't spew while the mutex is held!
VmmMsg( GetVirtualMemoryManager().m_Mutex, "Virtual Memory Manager [ reserved %uKB, committed %uKB ]: released %uKB @ 0x%08X\n",
GetVirtualMemoryManager().CountReservedPages() * VMM_PAGE_SIZE / VMM_KB,
GetVirtualMemoryManager().CountCommittedPages() * VMM_PAGE_SIZE / VMM_KB,
m_numMaxBytes / VMM_KB, m_pBase );
delete this;
}
IVirtualMemorySection * CVirtualMemoryManager::NewSection( byte *pBase, size_t numMaxBytes )
{
return new CVirtualMemorySectionImpl( pBase, numMaxBytes );
}
#endif
#ifdef VIRTUAL_MEMORY_MANAGER_SUPPORTED
IVirtualMemorySection * VirtualMemoryManager_AllocateVirtualMemorySection( size_t numMaxBytes )
{
return GetVirtualMemoryManager().AllocateVirtualMemorySection( numMaxBytes );
}
void VirtualMemoryManager_Shutdown()
{
GetVirtualMemoryManager().Shutdown();
}
IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress )
{
return GetVirtualMemoryManager().GetMemorySectionForAddress( pAddress );
}
void VirtualMemoryManager_GetStats( size_t &nReserved, size_t &nReservedMax, size_t &nCommitted, size_t &nCommittedMax )
{
GetVirtualMemoryManager().GetStats( nReserved, nReservedMax, nCommitted, nCommittedMax );
}
#else
IVirtualMemorySection * VirtualMemoryManager_AllocateVirtualMemorySection( size_t numMaxBytes )
{
return NULL;
}
void VirtualMemoryManager_Shutdown()
{
}
IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress )
{
return NULL;
}
#endif
#endif // !STEAM && !NO_MALLOC_OVERRIDE