Team Fortress 2 Source Code as on 22/4/2020
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.

277 lines
7.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #ifndef RESOURCEMANAGER_H
  7. #define RESOURCEMANAGER_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier0/threadtools.h"
  12. #include "utlmultilist.h"
  13. #include "utlvector.h"
  14. FORWARD_DECLARE_HANDLE( memhandle_t );
  15. #define INVALID_MEMHANDLE ((memhandle_t)0xffffffff)
  16. class CDataManagerBase
  17. {
  18. public:
  19. // public API
  20. // -----------------------------------------------------------------------------
  21. // memhandle_t CreateResource( params ) // implemented by derived class
  22. void DestroyResource( memhandle_t handle );
  23. // type-safe implementation in derived class
  24. //void *LockResource( memhandle_t handle );
  25. int UnlockResource( memhandle_t handle );
  26. void TouchResource( memhandle_t handle );
  27. void MarkAsStale( memhandle_t handle ); // move to head of LRU
  28. int LockCount( memhandle_t handle );
  29. int BreakLock( memhandle_t handle );
  30. int BreakAllLocks();
  31. // HACKHACK: For convenience - offers no lock protection
  32. // type-safe implementation in derived class
  33. //void *GetResource_NoLock( memhandle_t handle );
  34. unsigned int TargetSize();
  35. unsigned int AvailableSize();
  36. unsigned int UsedSize();
  37. void NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize );
  38. void SetTargetSize( unsigned int targetSize );
  39. // NOTE: flush is equivalent to Destroy
  40. unsigned int FlushAllUnlocked();
  41. unsigned int FlushToTargetSize();
  42. unsigned int FlushAll();
  43. unsigned int Purge( unsigned int nBytesToPurge );
  44. unsigned int EnsureCapacity( unsigned int size );
  45. // Thread lock
  46. virtual void Lock() {}
  47. virtual bool TryLock() { return true; }
  48. virtual void Unlock() {}
  49. // Iteration
  50. // -----------------------------------------------------------------------------
  51. // Debugging only!!!!
  52. void GetLRUHandleList( CUtlVector< memhandle_t >& list );
  53. void GetLockHandleList( CUtlVector< memhandle_t >& list );
  54. protected:
  55. // derived class must call these to implement public API
  56. unsigned short CreateHandle( bool bCreateLocked );
  57. memhandle_t StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize );
  58. void *GetResource_NoLock( memhandle_t handle );
  59. void *GetResource_NoLockNoLRUTouch( memhandle_t handle );
  60. void *LockResource( memhandle_t handle );
  61. // NOTE: you must call this from the destructor of the derived class! (will assert otherwise)
  62. void FreeAllLists() { FlushAll(); m_listsAreFreed = true; }
  63. CDataManagerBase( unsigned int maxSize );
  64. virtual ~CDataManagerBase();
  65. inline unsigned int MemTotal_Inline() const { return m_targetMemorySize; }
  66. inline unsigned int MemAvailable_Inline() const { return m_targetMemorySize - m_memUsed; }
  67. inline unsigned int MemUsed_Inline() const { return m_memUsed; }
  68. // Implemented by derived class:
  69. virtual void DestroyResourceStorage( void * ) = 0;
  70. virtual unsigned int GetRealSize( void * ) = 0;
  71. memhandle_t ToHandle( unsigned short index );
  72. unsigned short FromHandle( memhandle_t handle );
  73. void TouchByIndex( unsigned short memoryIndex );
  74. void * GetForFreeByIndex( unsigned short memoryIndex );
  75. // One of these is stored per active allocation
  76. struct resource_lru_element_t
  77. {
  78. resource_lru_element_t()
  79. {
  80. lockCount = 0;
  81. serial = 1;
  82. pStore = 0;
  83. }
  84. unsigned short lockCount;
  85. unsigned short serial;
  86. void *pStore;
  87. };
  88. unsigned int m_targetMemorySize;
  89. unsigned int m_memUsed;
  90. CUtlMultiList< resource_lru_element_t, unsigned short > m_memoryLists;
  91. unsigned short m_lruList;
  92. unsigned short m_lockList;
  93. unsigned short m_freeList;
  94. unsigned short m_listsAreFreed : 1;
  95. unsigned short m_unused : 15;
  96. };
  97. template< class STORAGE_TYPE, class CREATE_PARAMS, class LOCK_TYPE = STORAGE_TYPE *, class MUTEX_TYPE = CThreadNullMutex>
  98. class CDataManager : public CDataManagerBase
  99. {
  100. typedef CDataManagerBase BaseClass;
  101. public:
  102. CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>( unsigned int size = (unsigned)-1 ) : BaseClass(size) {}
  103. ~CDataManager<STORAGE_TYPE, CREATE_PARAMS, LOCK_TYPE, MUTEX_TYPE>()
  104. {
  105. // NOTE: This must be called in all implementations of CDataManager
  106. FreeAllLists();
  107. }
  108. // Use GetData() to translate pointer to LOCK_TYPE
  109. LOCK_TYPE LockResource( memhandle_t hMem )
  110. {
  111. void *pLock = BaseClass::LockResource( hMem );
  112. if ( pLock )
  113. {
  114. return StoragePointer(pLock)->GetData();
  115. }
  116. return NULL;
  117. }
  118. // Use GetData() to translate pointer to LOCK_TYPE
  119. LOCK_TYPE GetResource_NoLock( memhandle_t hMem )
  120. {
  121. void *pLock = const_cast<void *>(BaseClass::GetResource_NoLock( hMem ));
  122. if ( pLock )
  123. {
  124. return StoragePointer(pLock)->GetData();
  125. }
  126. return NULL;
  127. }
  128. // Use GetData() to translate pointer to LOCK_TYPE
  129. // Doesn't touch the memory LRU
  130. LOCK_TYPE GetResource_NoLockNoLRUTouch( memhandle_t hMem )
  131. {
  132. void *pLock = const_cast<void *>(BaseClass::GetResource_NoLockNoLRUTouch( hMem ));
  133. if ( pLock )
  134. {
  135. return StoragePointer(pLock)->GetData();
  136. }
  137. return NULL;
  138. }
  139. // Wrapper to match implementation of allocation with typed storage & alloc params.
  140. memhandle_t CreateResource( const CREATE_PARAMS &createParams, bool bCreateLocked = false )
  141. {
  142. BaseClass::EnsureCapacity(STORAGE_TYPE::EstimatedSize(createParams));
  143. unsigned short memoryIndex = BaseClass::CreateHandle( bCreateLocked );
  144. STORAGE_TYPE *pStore = STORAGE_TYPE::CreateResource( createParams );
  145. return BaseClass::StoreResourceInHandle( memoryIndex, pStore, pStore->Size() );
  146. }
  147. // Iteration. Must lock first
  148. memhandle_t GetFirstUnlocked()
  149. {
  150. unsigned node = m_memoryLists.Head(m_lruList);
  151. if ( node == m_memoryLists.InvalidIndex() )
  152. {
  153. return INVALID_MEMHANDLE;
  154. }
  155. return ToHandle( node );
  156. }
  157. memhandle_t GetFirstLocked()
  158. {
  159. unsigned node = m_memoryLists.Head(m_lockList);
  160. if ( node == m_memoryLists.InvalidIndex() )
  161. {
  162. return INVALID_MEMHANDLE;
  163. }
  164. return ToHandle( node );
  165. }
  166. memhandle_t GetNext( memhandle_t hPrev )
  167. {
  168. if ( hPrev == INVALID_MEMHANDLE )
  169. {
  170. return INVALID_MEMHANDLE;
  171. }
  172. unsigned short iNext = m_memoryLists.Next( FromHandle( hPrev ) );
  173. if ( iNext == m_memoryLists.InvalidIndex() )
  174. {
  175. return INVALID_MEMHANDLE;
  176. }
  177. return ToHandle( iNext );
  178. }
  179. MUTEX_TYPE &AccessMutex() { return m_mutex; }
  180. virtual void Lock() { m_mutex.Lock(); }
  181. virtual bool TryLock() { return m_mutex.TryLock(); }
  182. virtual void Unlock() { m_mutex.Unlock(); }
  183. private:
  184. STORAGE_TYPE *StoragePointer( void *pMem )
  185. {
  186. return static_cast<STORAGE_TYPE *>(pMem);
  187. }
  188. virtual void DestroyResourceStorage( void *pStore )
  189. {
  190. StoragePointer(pStore)->DestroyResource();
  191. }
  192. virtual unsigned int GetRealSize( void *pStore )
  193. {
  194. return StoragePointer(pStore)->Size();
  195. }
  196. MUTEX_TYPE m_mutex;
  197. };
  198. //-----------------------------------------------------------------------------
  199. inline unsigned short CDataManagerBase::FromHandle( memhandle_t handle )
  200. {
  201. unsigned int fullWord = (unsigned int)handle;
  202. unsigned short serial = fullWord>>16;
  203. unsigned short index = fullWord & 0xFFFF;
  204. index--;
  205. if ( m_memoryLists.IsValidIndex(index) && m_memoryLists[index].serial == serial )
  206. return index;
  207. return m_memoryLists.InvalidIndex();
  208. }
  209. inline int CDataManagerBase::LockCount( memhandle_t handle )
  210. {
  211. Lock();
  212. int result = 0;
  213. unsigned short memoryIndex = FromHandle(handle);
  214. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  215. {
  216. result = m_memoryLists[memoryIndex].lockCount;
  217. }
  218. Unlock();
  219. return result;
  220. }
  221. #endif // RESOURCEMANAGER_H