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.

410 lines
9.6 KiB

  1. //
  2. // Purpose:
  3. //
  4. // $NoKeywords: $
  5. //
  6. //=============================================================================//
  7. #include "basetypes.h"
  8. #include "datamanager.h"
  9. DECLARE_POINTER_HANDLE( memhandle_t );
  10. CDataManagerBase::CDataManagerBase( unsigned int maxSize )
  11. {
  12. m_targetMemorySize = maxSize;
  13. m_memUsed = 0;
  14. m_lruList = m_memoryLists.CreateList();
  15. m_lockList = m_memoryLists.CreateList();
  16. m_freeList = m_memoryLists.CreateList();
  17. m_listsAreFreed = 0;
  18. }
  19. CDataManagerBase::~CDataManagerBase()
  20. {
  21. Assert( m_listsAreFreed );
  22. }
  23. void CDataManagerBase::NotifySizeChanged( memhandle_t handle, unsigned int oldSize, unsigned int newSize )
  24. {
  25. Lock();
  26. m_memUsed += (int)newSize - (int)oldSize;
  27. Unlock();
  28. }
  29. void CDataManagerBase::SetTargetSize( unsigned int targetSize )
  30. {
  31. m_targetMemorySize = targetSize;
  32. }
  33. unsigned int CDataManagerBase::FlushAllUnlocked()
  34. {
  35. Lock();
  36. int nFlush = m_memoryLists.Count( m_lruList );
  37. void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
  38. CUtlVector<void *> destroyList( pScratch, nFlush );
  39. unsigned nBytesInitial = MemUsed_Inline();
  40. int node = m_memoryLists.Head(m_lruList);
  41. while ( node != m_memoryLists.InvalidIndex() )
  42. {
  43. int next = m_memoryLists.Next(node);
  44. m_memoryLists.Unlink( m_lruList, node );
  45. destroyList.AddToTail( GetForFreeByIndex( node ) );
  46. node = next;
  47. }
  48. Unlock();
  49. for ( int i = 0; i < nFlush; i++ )
  50. {
  51. DestroyResourceStorage( destroyList[i] );
  52. }
  53. return ( nBytesInitial - MemUsed_Inline() );
  54. }
  55. unsigned int CDataManagerBase::FlushToTargetSize()
  56. {
  57. return EnsureCapacity(0);
  58. }
  59. // Frees everything! The LRU AND the LOCKED items. This is only used to forcibly free the resources,
  60. // not to make space.
  61. unsigned int CDataManagerBase::FlushAll()
  62. {
  63. Lock();
  64. int nFlush = m_memoryLists.Count( m_lruList ) + m_memoryLists.Count( m_lockList );
  65. void **pScratch = (void **)_alloca( nFlush * sizeof(void *) );
  66. CUtlVector<void *> destroyList( pScratch, nFlush );
  67. unsigned result = MemUsed_Inline();
  68. int node;
  69. int nextNode;
  70. node = m_memoryLists.Head(m_lruList);
  71. while ( node != m_memoryLists.InvalidIndex() )
  72. {
  73. nextNode = m_memoryLists.Next(node);
  74. m_memoryLists.Unlink( m_lruList, node );
  75. destroyList.AddToTail( GetForFreeByIndex( node ) );
  76. node = nextNode;
  77. }
  78. node = m_memoryLists.Head(m_lockList);
  79. while ( node != m_memoryLists.InvalidIndex() )
  80. {
  81. nextNode = m_memoryLists.Next(node);
  82. m_memoryLists.Unlink( m_lockList, node );
  83. m_memoryLists[node].lockCount = 0;
  84. destroyList.AddToTail( GetForFreeByIndex( node ) );
  85. node = nextNode;
  86. }
  87. m_listsAreFreed = false;
  88. Unlock();
  89. for ( int i = 0; i < nFlush; i++ )
  90. {
  91. DestroyResourceStorage( destroyList[i] );
  92. }
  93. return result;
  94. }
  95. unsigned int CDataManagerBase::Purge( unsigned int nBytesToPurge )
  96. {
  97. unsigned int nTargetSize = MemUsed_Inline() - nBytesToPurge;
  98. // Check for underflow
  99. if ( MemUsed_Inline() < nBytesToPurge )
  100. nTargetSize = 0;
  101. unsigned int nImpliedCapacity = MemTotal_Inline() - nTargetSize;
  102. return EnsureCapacity( nImpliedCapacity );
  103. }
  104. void CDataManagerBase::DestroyResource( memhandle_t handle )
  105. {
  106. Lock();
  107. unsigned short index = FromHandle( handle );
  108. if ( !m_memoryLists.IsValidIndex(index) )
  109. {
  110. Unlock();
  111. return;
  112. }
  113. Assert( m_memoryLists[index].lockCount == 0 );
  114. if ( m_memoryLists[index].lockCount )
  115. BreakLock( handle );
  116. m_memoryLists.Unlink( m_lruList, index );
  117. void *p = GetForFreeByIndex( index );
  118. Unlock();
  119. DestroyResourceStorage( p );
  120. }
  121. void *CDataManagerBase::LockResource( memhandle_t handle )
  122. {
  123. AUTO_LOCK( *this );
  124. unsigned short memoryIndex = FromHandle(handle);
  125. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  126. {
  127. if ( m_memoryLists[memoryIndex].lockCount == 0 )
  128. {
  129. m_memoryLists.Unlink( m_lruList, memoryIndex );
  130. m_memoryLists.LinkToTail( m_lockList, memoryIndex );
  131. }
  132. Assert(m_memoryLists[memoryIndex].lockCount != (unsigned short)-1);
  133. m_memoryLists[memoryIndex].lockCount++;
  134. return m_memoryLists[memoryIndex].pStore;
  135. }
  136. return NULL;
  137. }
  138. int CDataManagerBase::UnlockResource( memhandle_t handle )
  139. {
  140. AUTO_LOCK( *this );
  141. unsigned short memoryIndex = FromHandle(handle);
  142. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  143. {
  144. Assert( m_memoryLists[memoryIndex].lockCount > 0 );
  145. if ( m_memoryLists[memoryIndex].lockCount > 0 )
  146. {
  147. m_memoryLists[memoryIndex].lockCount--;
  148. if ( m_memoryLists[memoryIndex].lockCount == 0 )
  149. {
  150. m_memoryLists.Unlink( m_lockList, memoryIndex );
  151. m_memoryLists.LinkToTail( m_lruList, memoryIndex );
  152. }
  153. }
  154. return m_memoryLists[memoryIndex].lockCount;
  155. }
  156. return 0;
  157. }
  158. void *CDataManagerBase::GetResource_NoLockNoLRUTouch( memhandle_t handle )
  159. {
  160. AUTO_LOCK( *this );
  161. unsigned short memoryIndex = FromHandle(handle);
  162. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  163. {
  164. return m_memoryLists[memoryIndex].pStore;
  165. }
  166. return NULL;
  167. }
  168. void *CDataManagerBase::GetResource_NoLock( memhandle_t handle )
  169. {
  170. AUTO_LOCK( *this );
  171. unsigned short memoryIndex = FromHandle(handle);
  172. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  173. {
  174. TouchByIndex( memoryIndex );
  175. return m_memoryLists[memoryIndex].pStore;
  176. }
  177. return NULL;
  178. }
  179. void CDataManagerBase::TouchResource( memhandle_t handle )
  180. {
  181. AUTO_LOCK( *this );
  182. TouchByIndex( FromHandle(handle) );
  183. }
  184. void CDataManagerBase::MarkAsStale( memhandle_t handle )
  185. {
  186. AUTO_LOCK( *this );
  187. unsigned short memoryIndex = FromHandle(handle);
  188. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  189. {
  190. if ( m_memoryLists[memoryIndex].lockCount == 0 )
  191. {
  192. m_memoryLists.Unlink( m_lruList, memoryIndex );
  193. m_memoryLists.LinkToHead( m_lruList, memoryIndex );
  194. }
  195. }
  196. }
  197. int CDataManagerBase::BreakLock( memhandle_t handle )
  198. {
  199. AUTO_LOCK( *this );
  200. unsigned short memoryIndex = FromHandle(handle);
  201. if ( memoryIndex != m_memoryLists.InvalidIndex() && m_memoryLists[memoryIndex].lockCount )
  202. {
  203. int nBroken = m_memoryLists[memoryIndex].lockCount;
  204. m_memoryLists[memoryIndex].lockCount = 0;
  205. m_memoryLists.Unlink( m_lockList, memoryIndex );
  206. m_memoryLists.LinkToTail( m_lruList, memoryIndex );
  207. return nBroken;
  208. }
  209. return 0;
  210. }
  211. int CDataManagerBase::BreakAllLocks()
  212. {
  213. AUTO_LOCK( *this );
  214. int nBroken = 0;
  215. int node;
  216. int nextNode;
  217. node = m_memoryLists.Head(m_lockList);
  218. while ( node != m_memoryLists.InvalidIndex() )
  219. {
  220. nBroken++;
  221. nextNode = m_memoryLists.Next(node);
  222. m_memoryLists[node].lockCount = 0;
  223. m_memoryLists.Unlink( m_lockList, node );
  224. m_memoryLists.LinkToTail( m_lruList, node );
  225. node = nextNode;
  226. }
  227. return nBroken;
  228. }
  229. unsigned short CDataManagerBase::CreateHandle( bool bCreateLocked )
  230. {
  231. AUTO_LOCK( *this );
  232. int memoryIndex = m_memoryLists.Head(m_freeList);
  233. unsigned short list = ( bCreateLocked ) ? m_lockList : m_lruList;
  234. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  235. {
  236. m_memoryLists.Unlink( m_freeList, memoryIndex );
  237. m_memoryLists.LinkToTail( list, memoryIndex );
  238. }
  239. else
  240. {
  241. memoryIndex = m_memoryLists.AddToTail( list );
  242. }
  243. if ( bCreateLocked )
  244. {
  245. m_memoryLists[memoryIndex].lockCount++;
  246. }
  247. return memoryIndex;
  248. }
  249. memhandle_t CDataManagerBase::StoreResourceInHandle( unsigned short memoryIndex, void *pStore, unsigned int realSize )
  250. {
  251. AUTO_LOCK( *this );
  252. resource_lru_element_t &mem = m_memoryLists[memoryIndex];
  253. mem.pStore = pStore;
  254. m_memUsed += realSize;
  255. return ToHandle(memoryIndex);
  256. }
  257. void CDataManagerBase::TouchByIndex( unsigned short memoryIndex )
  258. {
  259. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  260. {
  261. if ( m_memoryLists[memoryIndex].lockCount == 0 )
  262. {
  263. m_memoryLists.Unlink( m_lruList, memoryIndex );
  264. m_memoryLists.LinkToTail( m_lruList, memoryIndex );
  265. }
  266. }
  267. }
  268. memhandle_t CDataManagerBase::ToHandle( unsigned short index )
  269. {
  270. unsigned int hiword = m_memoryLists.Element(index).serial;
  271. hiword <<= 16;
  272. index++;
  273. return (memhandle_t)( hiword|index );
  274. }
  275. unsigned int CDataManagerBase::TargetSize()
  276. {
  277. return MemTotal_Inline();
  278. }
  279. unsigned int CDataManagerBase::AvailableSize()
  280. {
  281. return MemAvailable_Inline();
  282. }
  283. unsigned int CDataManagerBase::UsedSize()
  284. {
  285. return MemUsed_Inline();
  286. }
  287. // free resources until there is enough space to hold "size"
  288. unsigned int CDataManagerBase::EnsureCapacity( unsigned int size )
  289. {
  290. unsigned nBytesInitial = MemUsed_Inline();
  291. while ( MemUsed_Inline() > MemTotal_Inline() || MemAvailable_Inline() < size )
  292. {
  293. Lock();
  294. int lruIndex = m_memoryLists.Head( m_lruList );
  295. if ( lruIndex == m_memoryLists.InvalidIndex() )
  296. {
  297. Unlock();
  298. break;
  299. }
  300. m_memoryLists.Unlink( m_lruList, lruIndex );
  301. void *p = GetForFreeByIndex( lruIndex );
  302. Unlock();
  303. DestroyResourceStorage( p );
  304. }
  305. return ( nBytesInitial - MemUsed_Inline() );
  306. }
  307. // free this resource and move the handle to the free list
  308. void *CDataManagerBase::GetForFreeByIndex( unsigned short memoryIndex )
  309. {
  310. void *p = NULL;
  311. if ( memoryIndex != m_memoryLists.InvalidIndex() )
  312. {
  313. Assert( m_memoryLists[memoryIndex].lockCount == 0 );
  314. resource_lru_element_t &mem = m_memoryLists[memoryIndex];
  315. unsigned size = GetRealSize( mem.pStore );
  316. if ( size > m_memUsed )
  317. {
  318. ExecuteOnce( Warning( "Data manager 'used' memory incorrect\n" ) );
  319. size = m_memUsed;
  320. }
  321. m_memUsed -= size;
  322. p = mem.pStore;
  323. mem.pStore = NULL;
  324. mem.serial++;
  325. m_memoryLists.LinkToTail( m_freeList, memoryIndex );
  326. }
  327. return p;
  328. }
  329. // get a list of everything in the LRU
  330. void CDataManagerBase::GetLRUHandleList( CUtlVector< memhandle_t >& list )
  331. {
  332. for ( int node = m_memoryLists.Tail(m_lruList);
  333. node != m_memoryLists.InvalidIndex();
  334. node = m_memoryLists.Previous(node) )
  335. {
  336. list.AddToTail( ToHandle( node ) );
  337. }
  338. }
  339. // get a list of everything locked
  340. void CDataManagerBase::GetLockHandleList( CUtlVector< memhandle_t >& list )
  341. {
  342. for ( int node = m_memoryLists.Head(m_lockList);
  343. node != m_memoryLists.InvalidIndex();
  344. node = m_memoryLists.Next(node) )
  345. {
  346. list.AddToTail( ToHandle( node ) );
  347. }
  348. }