You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
8.0 KiB
296 lines
8.0 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#ifndef RESOURCEMANAGER_H |
|
#define RESOURCEMANAGER_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "tier0/threadtools.h" |
|
#include "utlmultilist.h" |
|
#include "utlvector.h" |
|
|
|
FORWARD_DECLARE_HANDLE( memhandle_t ); |
|
|
|
#define INVALID_MEMHANDLE ((memhandle_t)0xffffffff) |
|
|
|
class CDataManagerBase |
|
{ |
|
public: |
|
|
|
// public API |
|
// ----------------------------------------------------------------------------- |
|
// memhandle_t CreateResource( params ) // implemented by derived class |
|
void DestroyResource( memhandle_t handle ); |
|
|
|
// type-safe implementation in derived class |
|
//void *LockResource( memhandle_t handle ); |
|
int UnlockResource( memhandle_t handle ); |
|
void TouchResource( memhandle_t handle ); |
|
void MarkAsStale( memhandle_t handle ); // move to head of LRU |
|
|
|
int LockCount( memhandle_t handle ); |
|
int BreakLock( memhandle_t handle ); |
|
int BreakAllLocks(); |
|
|
|
// HACKHACK: For convenience - offers no lock protection |
|
// type-safe implementation in derived class |
|
//void *GetResource_NoLock( memhandle_t handle ); |
|
|
|
unsigned int TargetSize(); |
|
unsigned int AvailableSize(); |
|
unsigned int UsedSize(); |
|
|
|
void NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize ); |
|
|
|
void SetTargetSize( unsigned int targetSize ); |
|
|
|
// NOTE: flush is equivalent to Destroy |
|
unsigned int FlushAllUnlocked(); |
|
unsigned int FlushToTargetSize(); |
|
unsigned int FlushAll(); |
|
unsigned int Purge( unsigned int nBytesToPurge ); |
|
unsigned int EnsureCapacity( unsigned int size ); |
|
|
|
// Thread lock |
|
virtual void Lock() {} |
|
virtual bool TryLock() { return true; } |
|
virtual void Unlock() {} |
|
|
|
// Iteration |
|
|
|
// ----------------------------------------------------------------------------- |
|
|
|
void SetFreeOnDestruct( bool value ) { m_freeOnDestruct = value; } |
|
|
|
// Debugging only!!!! |
|
void GetLRUHandleList( CUtlVector< memhandle_t >& list ); |
|
void GetLockHandleList( CUtlVector< memhandle_t >& list ); |
|
|
|
|
|
protected: |
|
// derived class must call these to implement public API |
|
unsigned short CreateHandle( bool bCreateLocked ); |
|
memhandle_t StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize ); |
|
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; } |
|
|
|
CDataManagerBase( unsigned int maxSize ); |
|
virtual ~CDataManagerBase(); |
|
|
|
|
|
inline unsigned int MemTotal_Inline() const { return m_targetMemorySize; } |
|
inline unsigned int MemAvailable_Inline() const { return m_targetMemorySize - m_memUsed; } |
|
inline unsigned int MemUsed_Inline() const { return m_memUsed; } |
|
|
|
// Implemented by derived class: |
|
virtual void DestroyResourceStorage( void * ) = 0; |
|
virtual unsigned int GetRealSize( void * ) = 0; |
|
|
|
memhandle_t ToHandle( unsigned short index ); |
|
unsigned short FromHandle( memhandle_t handle ); |
|
|
|
void TouchByIndex( unsigned short memoryIndex ); |
|
void * GetForFreeByIndex( unsigned short memoryIndex ); |
|
|
|
// One of these is stored per active allocation |
|
struct resource_lru_element_t |
|
{ |
|
resource_lru_element_t() |
|
{ |
|
lockCount = 0; |
|
serial = 1; |
|
pStore = 0; |
|
} |
|
|
|
unsigned short lockCount; |
|
unsigned short serial; |
|
void *pStore; |
|
}; |
|
|
|
unsigned int m_targetMemorySize; |
|
unsigned int m_memUsed; |
|
|
|
CUtlMultiList< resource_lru_element_t, unsigned short > m_memoryLists; |
|
|
|
unsigned short m_lruList; |
|
unsigned short m_lockList; |
|
unsigned short m_freeList; |
|
unsigned short m_listsAreFreed : 1; |
|
unsigned short m_freeOnDestruct : 1; |
|
unsigned short m_unused : 14; |
|
|
|
}; |
|
|
|
template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE *, class MUTEX_TYPE = CThreadNullMutex> |
|
class CDataManager : public CDataManagerBase |
|
{ |
|
typedef CDataManagerBase BaseClass; |
|
public: |
|
|
|
CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>( unsigned int size = (unsigned)-1 ) : BaseClass(size) {} |
|
|
|
|
|
~CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>() |
|
{ |
|
// NOTE: This must be called in all implementations of CDataManager |
|
if ( m_freeOnDestruct ) |
|
{ |
|
FreeAllLists(); |
|
} |
|
} |
|
|
|
// Use GetData() to translate pointer to LOCK_TYPE |
|
LOCK_TYPE LockResource( memhandle_t hMem ) |
|
{ |
|
void *pLock = BaseClass::LockResource( hMem ); |
|
if ( pLock ) |
|
{ |
|
return StoragePointer(pLock)->GetData(); |
|
} |
|
|
|
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 ) |
|
{ |
|
void *pLock = const_cast<void *>(BaseClass::GetResource_NoLock( hMem )); |
|
if ( pLock ) |
|
{ |
|
return StoragePointer(pLock)->GetData(); |
|
} |
|
return NULL; |
|
} |
|
|
|
// Use GetData() to translate pointer to LOCK_TYPE |
|
// Doesn't touch the memory LRU |
|
LOCK_TYPE GetResource_NoLockNoLRUTouch( memhandle_t hMem ) |
|
{ |
|
void *pLock = const_cast<void *>(BaseClass::GetResource_NoLockNoLRUTouch( hMem )); |
|
if ( pLock ) |
|
{ |
|
return StoragePointer(pLock)->GetData(); |
|
} |
|
return NULL; |
|
} |
|
|
|
// Wrapper to match implementation of allocation with typed storage & alloc params. |
|
memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false ) |
|
{ |
|
BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams)); |
|
STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); |
|
AUTO_LOCK_( CDataManagerBase, *this ); |
|
unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); |
|
return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() ); |
|
} |
|
|
|
// Iteration. Must lock first |
|
memhandle_t GetFirstUnlocked() |
|
{ |
|
unsigned node = m_memoryLists.Head(m_lruList); |
|
if ( node == m_memoryLists.InvalidIndex() ) |
|
{ |
|
return INVALID_MEMHANDLE; |
|
} |
|
return ToHandle( node ); |
|
} |
|
|
|
memhandle_t GetFirstLocked() |
|
{ |
|
unsigned node = m_memoryLists.Head(m_lockList); |
|
if ( node == m_memoryLists.InvalidIndex() ) |
|
{ |
|
return INVALID_MEMHANDLE; |
|
} |
|
return ToHandle( node ); |
|
} |
|
|
|
memhandle_t GetNext( memhandle_t hPrev ) |
|
{ |
|
if ( hPrev == INVALID_MEMHANDLE ) |
|
{ |
|
return INVALID_MEMHANDLE; |
|
} |
|
|
|
unsigned short iNext = m_memoryLists.Next( FromHandle( hPrev ) ); |
|
if ( iNext == m_memoryLists.InvalidIndex() ) |
|
{ |
|
return INVALID_MEMHANDLE; |
|
} |
|
|
|
return ToHandle( iNext ); |
|
} |
|
|
|
MUTEX_TYPE &AccessMutex() { return m_mutex; } |
|
virtual void Lock() { m_mutex.Lock(); } |
|
virtual bool TryLock() { return m_mutex.TryLock(); } |
|
virtual void Unlock() { m_mutex.Unlock(); } |
|
|
|
private: |
|
STORAGE_TYPE *StoragePointer( void *pMem ) |
|
{ |
|
return static_cast<STORAGE_TYPE *>(pMem); |
|
} |
|
|
|
virtual void DestroyResourceStorage( void *pStore ) |
|
{ |
|
StoragePointer(pStore)->DestroyResource(); |
|
} |
|
|
|
virtual unsigned int GetRealSize( void *pStore ) |
|
{ |
|
return StoragePointer(pStore)->Size(); |
|
} |
|
|
|
MUTEX_TYPE m_mutex; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle ) |
|
{ |
|
unsigned int fullWord = (unsigned int)reinterpret_cast<uintp>( handle ); |
|
unsigned short serial = fullWord>>16; |
|
unsigned short index = fullWord & 0xFFFF; |
|
index--; |
|
if ( m_memoryLists.IsValidIndex(index) && m_memoryLists[index].serial == serial ) |
|
return index; |
|
return m_memoryLists.InvalidIndex(); |
|
} |
|
|
|
inline int CDataManagerBase::LockCount( memhandle_t handle ) |
|
{ |
|
Lock(); |
|
int result = 0; |
|
unsigned short memoryIndex = FromHandle(handle); |
|
if ( memoryIndex != m_memoryLists.InvalidIndex() ) |
|
{ |
|
result = m_memoryLists[memoryIndex].lockCount; |
|
} |
|
Unlock(); |
|
return result; |
|
} |
|
|
|
|
|
#endif // RESOURCEMANAGER_H
|
|
|