initial
This commit is contained in:
296
public/tier1/datamanager.h
Normal file
296
public/tier1/datamanager.h
Normal file
@@ -0,0 +1,296 @@
|
||||
//========= Copyright <20> 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
|
||||
Reference in New Issue
Block a user