diff options
Diffstat (limited to 'public/tier1/datamanager.h')
| -rw-r--r-- | public/tier1/datamanager.h | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/public/tier1/datamanager.h b/public/tier1/datamanager.h new file mode 100644 index 0000000..8803054 --- /dev/null +++ b/public/tier1/datamanager.h @@ -0,0 +1,277 @@ +//========= Copyright 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 + + // ----------------------------------------------------------------------------- + + // 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 ); + + // 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_unused : 15; + +}; + +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 + 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; + } + + // 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)); + unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked ); + STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams ); + 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)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 |