Leaked source code of windows server 2003
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.

337 lines
9.6 KiB

  1. // --------------------------------------------------------------------------------
  2. // MemCache.h
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // --------------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include "memcache.h"
  7. #include <BadStrFunctions.h>
  8. // --------------------------------------------------------------------------------
  9. // CELLSIZE
  10. // --------------------------------------------------------------------------------
  11. #define CELLSIZE(_ulIndex) ((DWORD)(_ulIndex + m_cbMin))
  12. // --------------------------------------------------------------------------------
  13. // CELLINDEX
  14. // --------------------------------------------------------------------------------
  15. #define CELLINDEX(_cb) ((ULONG)(_cb - m_cbMin))
  16. // --------------------------------------------------------------------------------
  17. // ISVALIDITEM
  18. // --------------------------------------------------------------------------------
  19. #define ISVALIDITEM(_pv, _iCell) \
  20. (FALSE == IsBadReadPtr(_pv, CELLSIZE(_iCell)) && \
  21. FALSE == IsBadWritePtr(_pv, CELLSIZE(_iCell)) && \
  22. m_pMalloc->GetSize(_pv) >= CELLSIZE(_iCell))
  23. // --------------------------------------------------------------------------------
  24. // CMemoryCache::CMemoryCache
  25. // --------------------------------------------------------------------------------
  26. CMemoryCache::CMemoryCache(IMalloc *pMalloc, ULONG cbMin /* =0 */, ULONG cbCacheMax /* =131072 */)
  27. : m_pMalloc(pMalloc), m_cbMin(cbMin + sizeof(MEMCACHEITEM)), m_cbCacheMax(cbCacheMax)
  28. {
  29. m_cRef = 1;
  30. m_cbCacheCur = 0;
  31. ZeroMemory(m_rgCell, sizeof(m_rgCell));
  32. #ifdef DEBUG
  33. ZeroMemory(&m_rMetric, sizeof(MEMCACHEMETRIC));
  34. #endif
  35. InitializeCriticalSection(&m_cs);
  36. }
  37. // --------------------------------------------------------------------------------
  38. // CMemoryCache::CMemoryCache
  39. // --------------------------------------------------------------------------------
  40. CMemoryCache::~CMemoryCache(void)
  41. {
  42. #ifdef DEBUG
  43. DebugTrace("InetComm - CMemoryCache: cAlloc = %d\n", m_rMetric.cAlloc);
  44. DebugTrace("InetComm - CMemoryCache: cAllocCache = %d\n", m_rMetric.cAllocCache);
  45. DebugTrace("InetComm - CMemoryCache: cbAlloc = %d bytes\n", m_rMetric.cbAlloc);
  46. DebugTrace("InetComm - CMemoryCache: cFree = %d\n", m_rMetric.cFree);
  47. DebugTrace("InetComm - CMemoryCache: cbFree = %d bytes\n", m_rMetric.cbFree);
  48. DebugTrace("InetComm - CMemoryCache: cbCacheMax = %d bytes\n", m_rMetric.cbCacheMax);
  49. DebugTrace("InetComm - CMemoryCache: cFreeFull = %d\n", m_rMetric.cFreeFull);
  50. DebugTrace("InetComm - CMemoryCache: cLookAhead = %d\n", m_rMetric.cLookAhead);
  51. DebugTrace("InetComm - CMemoryCache: Average Look Aheads = %d\n", (m_rMetric.cLookAhead / m_rMetric.cAlloc));
  52. DebugTrace("InetComm - CMemoryCache: cMostFree = %d\n", m_rMetric.cMostFree);
  53. DebugTrace("InetComm - CMemoryCache: cbMostFree = %d bytes\n", m_rMetric.cbMostFree);
  54. DebugTrace("InetComm - CMemoryCache: cMostAlloc = %d\n", m_rMetric.cMostAlloc);
  55. DebugTrace("InetComm - CMemoryCache: cbMostAlloc = %d bytes\n", m_rMetric.cbMostAlloc);
  56. #endif
  57. HeapMinimize();
  58. DeleteCriticalSection(&m_cs);
  59. }
  60. // --------------------------------------------------------------------------------
  61. // CMemoryCache::AddRef
  62. // --------------------------------------------------------------------------------
  63. STDMETHODIMP_(ULONG) CMemoryCache::AddRef(void)
  64. {
  65. return ++m_cRef;
  66. }
  67. // --------------------------------------------------------------------------------
  68. // CMemoryCache::CMemoryCache
  69. // --------------------------------------------------------------------------------
  70. STDMETHODIMP_(ULONG) CMemoryCache::Release(void)
  71. {
  72. if (0 != --m_cRef)
  73. return m_cRef;
  74. delete this;
  75. return 0;
  76. }
  77. // --------------------------------------------------------------------------------
  78. // CMemoryCache::Alloc
  79. // --------------------------------------------------------------------------------
  80. STDMETHODIMP_(LPVOID) CMemoryCache::Alloc(DWORD cbAlloc)
  81. {
  82. // Locals
  83. ULONG iCell;
  84. ULONG iCellMax;
  85. LPVOID pvAlloc;
  86. // No Work
  87. if (0 == cbAlloc)
  88. return NULL;
  89. // Count Number of allocations
  90. INCMETRIC(cAlloc, 1);
  91. INCMETRIC(cbAlloc, cbAlloc);
  92. // Get Index
  93. iCell = CELLINDEX(cbAlloc);
  94. // Out of range
  95. if (iCell >= CACHECELLS)
  96. {
  97. // Normal Alloc
  98. return m_pMalloc->Alloc(cbAlloc);
  99. }
  100. // Thread Safety
  101. EnterCriticalSection(&m_cs);
  102. // Compute iMax
  103. iCellMax = min(iCell + 10, CACHECELLS);
  104. // Try to allocate within 0 - 10 bytes of iCell
  105. while(iCell < iCellMax)
  106. {
  107. // Set pvAlloc
  108. pvAlloc = m_rgCell[iCell].pvItemHead;
  109. // Done
  110. if (pvAlloc)
  111. break;
  112. // Next
  113. iCell++;
  114. // Metric
  115. INCMETRIC(cLookAhead, 1);
  116. }
  117. // Is there memory here
  118. if (NULL == pvAlloc)
  119. {
  120. // Thread Safety
  121. LeaveCriticalSection(&m_cs);
  122. // Normal Alloc
  123. return m_pMalloc->Alloc(cbAlloc);
  124. }
  125. // Count Number of allocations
  126. INCMETRIC(cAllocCache, 1);
  127. INCMETRIC(cbAllocCache, CELLSIZE(iCell));
  128. // Adjust the Chain
  129. m_rgCell[iCell].pvItemHead = ((LPMEMCACHEITEM)pvAlloc)->pvItemNext;
  130. // Reduce the Size
  131. m_cbCacheCur -= CELLSIZE(iCell);
  132. #ifdef DEBUG
  133. memset(pvAlloc, 0xFF, cbAlloc);
  134. m_rgCell[iCell].cAlloc++;
  135. if (m_rgCell[iCell].cAlloc > m_rMetric.cMostAlloc)
  136. {
  137. m_rMetric.cMostAlloc = m_rgCell[iCell].cAlloc;
  138. m_rMetric.cbMostAlloc = CELLSIZE(iCell);
  139. }
  140. #endif
  141. // Thread Safety
  142. LeaveCriticalSection(&m_cs);
  143. // Done
  144. return pvAlloc;
  145. }
  146. // --------------------------------------------------------------------------------
  147. // CMemoryCache::Realloc
  148. // --------------------------------------------------------------------------------
  149. STDMETHODIMP_(LPVOID) CMemoryCache::Realloc(LPVOID pv, DWORD cbAlloc)
  150. {
  151. // Locals
  152. ULONG cbCurrent;
  153. LPVOID pvAlloc;
  154. // Free
  155. if (0 == cbAlloc)
  156. {
  157. // Free pv
  158. Free(pv);
  159. // Done
  160. return NULL;
  161. }
  162. // No pv
  163. if (NULL == pv)
  164. {
  165. // Just Alloc
  166. return Alloc(cbAlloc);
  167. }
  168. // If we have Get Size of pv
  169. cbCurrent = m_pMalloc->GetSize(pv);
  170. // Allocate
  171. pvAlloc = Alloc(cbAlloc);
  172. // Failure
  173. if (NULL == pvAlloc)
  174. return NULL;
  175. // Copy
  176. CopyMemory(pvAlloc, pv, min(cbCurrent, cbAlloc));
  177. // Done
  178. return pvAlloc;
  179. }
  180. // --------------------------------------------------------------------------------
  181. // CMemoryCache::Free
  182. // --------------------------------------------------------------------------------
  183. STDMETHODIMP_(VOID) CMemoryCache::Free(LPVOID pvFree)
  184. {
  185. // Locals
  186. ULONG iCell;
  187. ULONG cbFree;
  188. MEMCACHEITEM rItem;
  189. // No Work
  190. if (NULL == pvFree)
  191. return;
  192. // Get the size
  193. cbFree = m_pMalloc->GetSize(pvFree);
  194. // Metrics
  195. INCMETRIC(cFree, 1);
  196. INCMETRIC(cbFree, cbFree);
  197. // Lets put it into the cell
  198. iCell = CELLINDEX(cbFree);
  199. // Verify the buffer
  200. Assert(ISVALIDITEM(pvFree, iCell));
  201. // Thread Safety
  202. EnterCriticalSection(&m_cs);
  203. // Size of buffer is out of range or the cache has reached its max
  204. if (cbFree < m_cbMin || cbFree - m_cbMin > CACHECELLS || m_cbCacheCur + cbFree > m_cbCacheMax)
  205. {
  206. // Stats
  207. INCMETRIC(cFreeFull, 1);
  208. // Thread Safety
  209. LeaveCriticalSection(&m_cs);
  210. // Free It
  211. m_pMalloc->Free(pvFree);
  212. // Done
  213. return;
  214. }
  215. // Set Next
  216. rItem.pvItemNext = m_rgCell[iCell].pvItemHead;
  217. #ifdef DEBUG
  218. memset(pvFree, 0xDD, cbFree);
  219. #endif
  220. // Write this into the buffer
  221. CopyMemory(pvFree, &rItem, sizeof(MEMCACHEITEM));
  222. // Reset pvItemHead
  223. m_rgCell[iCell].pvItemHead = pvFree;
  224. // Increment m_cbCacheCur
  225. m_cbCacheCur += cbFree;
  226. #ifdef DEBUG
  227. if (m_cbCacheCur > m_rMetric.cbCacheMax)
  228. m_rMetric.cbCacheMax = m_cbCacheCur;
  229. m_rgCell[iCell].cFree++;
  230. if (m_rgCell[iCell].cFree > m_rMetric.cMostFree)
  231. {
  232. m_rMetric.cMostFree = m_rgCell[iCell].cFree;
  233. m_rMetric.cbMostFree = CELLSIZE(iCell);
  234. }
  235. #endif
  236. // Thread Safety
  237. LeaveCriticalSection(&m_cs);
  238. }
  239. // --------------------------------------------------------------------------------
  240. // CMemoryCache::HeapMinimize
  241. // --------------------------------------------------------------------------------
  242. STDMETHODIMP_(VOID) CMemoryCache::HeapMinimize(void)
  243. {
  244. // Locals
  245. LPVOID pvCurr;
  246. LPVOID pvNext;
  247. ULONG i;
  248. // Thread Safety
  249. EnterCriticalSection(&m_cs);
  250. // Walk throught the cells
  251. for (i=0; i<ARRAYSIZE(m_rgCell); i++)
  252. {
  253. // Set Current
  254. pvCurr = m_rgCell[i].pvItemHead;
  255. // Call the Chain of Buffers
  256. while(pvCurr)
  257. {
  258. // Valid Buffer
  259. Assert(ISVALIDITEM(pvCurr, i));
  260. // Get Next
  261. pvNext = ((LPMEMCACHEITEM)pvCurr)->pvItemNext;
  262. // Free this buffer
  263. m_pMalloc->Free(pvCurr);
  264. // Goto Next
  265. pvCurr = pvNext;
  266. }
  267. // Clear the cell
  268. m_rgCell[i].pvItemHead = NULL;
  269. }
  270. // Minimize internal cache
  271. m_pMalloc->HeapMinimize();
  272. // Thread Safety
  273. LeaveCriticalSection(&m_cs);
  274. }