Source code of Windows XP (NT5)
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.

276 lines
6.2 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1997 **/
  4. /**********************************************************************/
  5. /*
  6. manodel.cxx
  7. This module contains the code for a memory allocation class that doesn't
  8. delete memory until the class goes away.
  9. FILE HISTORY:
  10. 1/9/98 michth created
  11. */
  12. #include "precomp.hxx"
  13. #define DLL_IMPLEMENTATION
  14. #define IMPLEMENTATION_EXPORT
  15. #include <manodel.hxx>
  16. MEMORY_ALLOC_NO_DELETE::MEMORY_ALLOC_NO_DELETE( DWORD dwAllocSize,
  17. DWORD dwAlignment,
  18. BOOL bSortFree,
  19. DWORD dwMinBlockMultiple,
  20. HANDLE hHeap):
  21. m_dwAllocSize(dwAllocSize),
  22. m_dwAlignment(dwAlignment),
  23. m_dwBlockMultiple(dwMinBlockMultiple),
  24. m_hHeap(hHeap),
  25. m_dwNumAlloced(0),
  26. m_dwNumFree(0),
  27. m_dwNumBlocks(0),
  28. m_bSortFree(bSortFree),
  29. m_pvBlockList(NULL),
  30. m_pvFreeList(NULL)
  31. {
  32. //
  33. // Make sure there really is an alignment
  34. //
  35. if (m_dwAlignment == 0) {
  36. m_dwAlignment = 4;
  37. }
  38. //
  39. // Now Make sure the alignment is a multiple of 4
  40. //
  41. AlignAdjust(m_dwAlignment, 4);
  42. //
  43. // Align the size
  44. //
  45. AlignAdjust(m_dwAllocSize, m_dwAlignment);
  46. //
  47. // Calculate the Max Block Multiple
  48. //
  49. if (m_dwAllocSize <= 100) {
  50. m_dwMaxBlockMultiple = 2000 / m_dwAllocSize;
  51. }
  52. else if (m_dwAllocSize <= 1000) {
  53. m_dwMaxBlockMultiple = 10;
  54. }
  55. else {
  56. m_dwMaxBlockMultiple = 5;
  57. }
  58. //
  59. // Determine space to alloc for block header
  60. //
  61. m_dwBlockHeaderSpace = BLOCK_HEADER_SIZE;
  62. AlignAdjust(m_dwBlockHeaderSpace, LESSER_OF(8, m_dwAlignment));
  63. if (m_dwAlignment > 8) {
  64. m_dwAlignBytes = m_dwAlignment - 8;
  65. }
  66. else {
  67. m_dwAlignBytes = 0;
  68. }
  69. //
  70. // Get Heap Handle if not passed in
  71. //
  72. if (m_hHeap == USE_PROCESS_HEAP) {
  73. m_hHeap = GetProcessHeap();
  74. }
  75. DBG_ASSERT(m_hHeap != NULL);
  76. INITIALIZE_CRITICAL_SECTION(&m_csLock);
  77. SET_CRITICAL_SECTION_SPIN_COUNT( &m_csLock, 4000);
  78. }
  79. MEMORY_ALLOC_NO_DELETE::~MEMORY_ALLOC_NO_DELETE()
  80. {
  81. LockThis();
  82. PVOID pvIndex, pvNext;
  83. for (pvIndex = m_pvBlockList;
  84. pvIndex != NULL;
  85. pvIndex = pvNext) {
  86. pvNext = *((PVOID *)pvIndex);
  87. HeapFree(m_hHeap,
  88. /* Flags */ 0,
  89. pvIndex);
  90. }
  91. UnlockThis();
  92. DeleteCriticalSection(&m_csLock);
  93. }
  94. PVOID
  95. MEMORY_ALLOC_NO_DELETE::Alloc()
  96. {
  97. PVOID pvAlloc = NULL;
  98. LockThis();
  99. pvAlloc = GetAllocFromFreeList();
  100. if (pvAlloc == NULL) {
  101. if (AllocBlock()) {
  102. pvAlloc = GetAllocFromFreeList();
  103. DBG_ASSERT (pvAlloc != NULL);
  104. }
  105. }
  106. UnlockThis();
  107. return pvAlloc;
  108. }
  109. BOOL
  110. MEMORY_ALLOC_NO_DELETE::Free (PVOID pvMem)
  111. {
  112. if (pvMem != NULL) {
  113. LockThis();
  114. if (!m_bSortFree) {
  115. *((PVOID *)pvMem) = m_pvFreeList;
  116. m_pvFreeList = pvMem;
  117. }
  118. else {
  119. //
  120. // Sort the free list.
  121. // Sort in reverse order, since AddBlockToFreeList
  122. // puts them on in reverse order.
  123. //
  124. PVOID *ppvIndex;
  125. for (ppvIndex = &m_pvFreeList;
  126. (*ppvIndex != NULL) && (*ppvIndex > pvMem);
  127. ppvIndex = *(PVOID **)(ppvIndex)) {
  128. }
  129. *(PVOID *)pvMem = *ppvIndex;
  130. *ppvIndex = pvMem;
  131. }
  132. m_dwNumFree++;
  133. UnlockThis();
  134. }
  135. return TRUE;
  136. }
  137. VOID
  138. MEMORY_ALLOC_NO_DELETE::GetNewBlockMultiple()
  139. {
  140. DWORD dwCalculatedMultiple = LESSER_OF((m_dwNumAlloced / 5), m_dwMaxBlockMultiple);
  141. m_dwBlockMultiple = GREATER_OF(m_dwBlockMultiple, dwCalculatedMultiple);
  142. }
  143. PVOID
  144. MEMORY_ALLOC_NO_DELETE::GetAllocFromFreeList()
  145. {
  146. PVOID pvAlloc = m_pvFreeList;
  147. //
  148. // Remove from free list if necessary
  149. //
  150. if (m_pvFreeList != NULL) {
  151. m_pvFreeList = *((PVOID *)m_pvFreeList);
  152. m_dwNumFree--;
  153. }
  154. return pvAlloc;
  155. }
  156. BOOL
  157. MEMORY_ALLOC_NO_DELETE::AllocBlock()
  158. {
  159. PVOID pvNewBlock = NULL;
  160. DWORD dwBlockSize;
  161. BOOL bReturn = FALSE;
  162. GetNewBlockMultiple();
  163. dwBlockSize = (m_dwAllocSize * m_dwBlockMultiple) +
  164. m_dwBlockHeaderSpace + m_dwAlignBytes;
  165. pvNewBlock = HeapAlloc(m_hHeap,
  166. /* Flags */ 0,
  167. dwBlockSize);
  168. if (pvNewBlock == NULL) {
  169. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  170. }
  171. else {
  172. *((PVOID *)pvNewBlock) = m_pvBlockList;
  173. m_pvBlockList = pvNewBlock;
  174. AddBlockToFreeList(pvNewBlock);
  175. m_dwNumAlloced += m_dwBlockMultiple;
  176. m_dwNumBlocks++;
  177. bReturn = TRUE;
  178. }
  179. return bReturn;
  180. }
  181. VOID
  182. MEMORY_ALLOC_NO_DELETE::AddBlockToFreeList(PVOID pvNewBlock)
  183. {
  184. DBG_ASSERT(pvNewBlock != NULL);
  185. PBYTE pbFirstAlloc = (PBYTE)pvNewBlock + m_dwBlockHeaderSpace;
  186. if (m_dwAlignment > 8) {
  187. //
  188. // May need to put some bytes in front to align allocs
  189. // Find the first place that is aligned.
  190. //
  191. ULONG_PTR firstAlloc = (ULONG_PTR)pbFirstAlloc;
  192. AlignAdjust(firstAlloc, (ULONG_PTR)m_dwAlignment);
  193. pbFirstAlloc = (PBYTE)firstAlloc;
  194. }
  195. PVOID pvEnd = (PVOID)((PBYTE)pbFirstAlloc + (m_dwBlockMultiple * m_dwAllocSize));
  196. for (PVOID pvAllocIndex = (PVOID)pbFirstAlloc;
  197. pvAllocIndex < pvEnd;
  198. pvAllocIndex = (PVOID)((PBYTE)pvAllocIndex + m_dwAllocSize)) {
  199. *((PVOID *)pvAllocIndex) = m_pvFreeList;
  200. m_pvFreeList = pvAllocIndex;
  201. }
  202. m_dwNumFree += m_dwBlockMultiple;
  203. }
  204. VOID
  205. MEMORY_ALLOC_NO_DELETE::AlignAdjust(DWORD &rdwSize, DWORD dwAlignment)
  206. {
  207. if ((rdwSize % dwAlignment != 0)) {
  208. rdwSize &= (0xFFFFFFFF - dwAlignment + 1);
  209. rdwSize += dwAlignment;
  210. }
  211. }
  212. #ifdef _WIN64
  213. VOID
  214. MEMORY_ALLOC_NO_DELETE::AlignAdjust(ULONG_PTR &rSize, ULONG_PTR Alignment)
  215. {
  216. rSize = ( rSize + Alignment - 1 ) & ~( Alignment - 1 );
  217. }
  218. #endif