Counter Strike : Global Offensive Source Code
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.

435 lines
10 KiB

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