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.

321 lines
7.7 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: fixedpool.cpp
  6. * Content: fixed size pool manager
  7. *
  8. * History:
  9. * Date By Reason
  10. * ====== == ======
  11. * 07-21-2001 masonb Created
  12. * 10-16-2001 vanceo Tweaked release locking and freed memory if Alloc function fails
  13. * 02-22-2002 simonpow Removed c'tor and d'tor, which weren't consistently being called
  14. ***************************************************************************/
  15. #include "dncmni.h"
  16. #undef DPF_MODNAME
  17. #define DPF_MODNAME "CFixedPool::Initialize"
  18. BOOL CFixedPool::Initialize(DWORD dwElementSize,
  19. FN_BLOCKALLOC pfnBlockAlloc,
  20. FN_BLOCKGET pfnBlockGet,
  21. FN_BLOCKRELEASE pfnBlockRelease,
  22. FN_BLOCKDEALLOC pfnBlockDeAlloc)
  23. {
  24. // Ensure that we stay heap aligned for SLISTs
  25. #ifdef _WIN64
  26. DBG_CASSERT(sizeof(FIXED_POOL_ITEM) % 16 == 0);
  27. #else // !_WIN64
  28. DBG_CASSERT(sizeof(FIXED_POOL_ITEM) % 8 == 0);
  29. #endif // _WIN64
  30. #ifdef DBG
  31. if (!DNInitializeCriticalSection(&m_csInUse))
  32. {
  33. DPFERR("Failed initializing pool critical section");
  34. m_fInitialized = FALSE;
  35. return FALSE;
  36. }
  37. m_pInUseElements = NULL;
  38. #endif // DBG
  39. DNInitializeSListHead(&m_slAvailableElements);
  40. m_pfnBlockAlloc = pfnBlockAlloc;
  41. m_pfnBlockGet = pfnBlockGet;
  42. m_pfnBlockRelease = pfnBlockRelease;
  43. m_pfnBlockDeAlloc = pfnBlockDeAlloc;
  44. m_dwItemSize = dwElementSize;
  45. #ifdef DBG
  46. m_lAllocated = 0;
  47. #endif // DBG
  48. m_lInUse = 0;
  49. m_fInitialized = TRUE;
  50. return TRUE;
  51. }
  52. #undef DPF_MODNAME
  53. #define DPF_MODNAME "CFixedPool::DeInitialize"
  54. VOID CFixedPool::DeInitialize()
  55. {
  56. FIXED_POOL_ITEM* pItem;
  57. DNSLIST_ENTRY* pslEntry;
  58. if (m_fInitialized == FALSE)
  59. {
  60. return;
  61. }
  62. // Clean up entries sitting in the pool
  63. pslEntry = DNInterlockedPopEntrySList(&m_slAvailableElements);
  64. while(pslEntry != NULL)
  65. {
  66. pItem = CONTAINING_RECORD(pslEntry, FIXED_POOL_ITEM, slist);
  67. if (m_pfnBlockDeAlloc != NULL)
  68. {
  69. (*m_pfnBlockDeAlloc)(pItem + 1);
  70. }
  71. DNFree(pItem);
  72. #ifdef DBG
  73. DNInterlockedDecrement(&m_lAllocated);
  74. DNASSERT(m_lAllocated >=0);
  75. #endif // DBG
  76. pslEntry = DNInterlockedPopEntrySList(&m_slAvailableElements);
  77. }
  78. #ifdef DBG
  79. DumpLeaks();
  80. DNDeleteCriticalSection(&m_csInUse);
  81. #endif // DBG
  82. m_fInitialized = FALSE;
  83. }
  84. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  85. #undef DPF_MODNAME
  86. #define DPF_MODNAME "CFixedPool::Preallocate"
  87. DWORD CFixedPool::Preallocate( DWORD dwCount, PVOID pvContext )
  88. {
  89. DWORD dwAllocated;
  90. FIXED_POOL_ITEM* pItem;
  91. DNASSERT(m_fInitialized == TRUE);
  92. for(dwAllocated = 0; dwAllocated < dwCount; dwAllocated++)
  93. {
  94. pItem = (FIXED_POOL_ITEM*)DNMalloc(sizeof(FIXED_POOL_ITEM) + m_dwItemSize);
  95. if (pItem == NULL)
  96. {
  97. DPFERR("Out of memory allocating new item for pool");
  98. return NULL;
  99. }
  100. if ((m_pfnBlockAlloc != NULL) && !(*m_pfnBlockAlloc)(pItem + 1, pvContext))
  101. {
  102. DPFERR("Alloc function returned FALSE allocating new item for pool");
  103. // Can't stick the new item as available in the pool since pool assumes Alloc has
  104. // succeeded when it's in the pool.
  105. DNFree(pItem);
  106. break;
  107. }
  108. #ifdef DBG
  109. DNInterlockedIncrement(&m_lAllocated);
  110. #endif // DBG
  111. DNInterlockedPushEntrySList(&m_slAvailableElements, &pItem->slist);
  112. }
  113. return dwAllocated;
  114. }
  115. #endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
  116. #undef DPF_MODNAME
  117. #define DPF_MODNAME "CFixedPool::Get"
  118. VOID* CFixedPool::Get( PVOID pvContext )
  119. {
  120. FIXED_POOL_ITEM* pItem;
  121. DNSLIST_ENTRY* pslEntry;
  122. DNASSERT(m_fInitialized == TRUE);
  123. pslEntry = DNInterlockedPopEntrySList(&m_slAvailableElements);
  124. if (pslEntry == NULL)
  125. {
  126. #ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
  127. DPFX(DPFPREP, 0, "No more items in pool!");
  128. DNASSERTX(! "No more items in pool!", 2);
  129. return NULL;
  130. #else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  131. pItem = (FIXED_POOL_ITEM*)DNMalloc(sizeof(FIXED_POOL_ITEM) + m_dwItemSize);
  132. if (pItem == NULL)
  133. {
  134. DPFERR("Out of memory allocating new item for pool!");
  135. return NULL;
  136. }
  137. if ((m_pfnBlockAlloc != NULL) && !(*m_pfnBlockAlloc)(pItem + 1, pvContext))
  138. {
  139. DPFERR("Alloc function returned FALSE allocating new item for pool!");
  140. // Can't stick the new item as available in the pool since pool assumes Alloc has
  141. // succeeded when it's in the pool.
  142. DNFree(pItem);
  143. return NULL;
  144. }
  145. #ifdef DBG
  146. DNInterlockedIncrement(&m_lAllocated);
  147. #endif // DBG
  148. #endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
  149. }
  150. else
  151. {
  152. pItem = CONTAINING_RECORD(pslEntry, FIXED_POOL_ITEM, slist);
  153. }
  154. // At this point we have an item whether it was newly created or pulled from the pool.
  155. InterlockedIncrement(&m_lInUse);
  156. DNASSERT(m_lInUse > 0);
  157. #ifdef DBG
  158. // Note the callstack and add the item to the in use list.
  159. pItem->callstack.NoteCurrentCallStack();
  160. DNEnterCriticalSection(&m_csInUse);
  161. pItem->slist.Next = m_pInUseElements;
  162. m_pInUseElements = &pItem->slist;
  163. DNLeaveCriticalSection(&m_csInUse);
  164. // In debug only, store the pool the item belongs to on the item for checking upon release
  165. pItem->pThisPool = this;
  166. #endif // DBG
  167. if (m_pfnBlockGet != NULL)
  168. {
  169. (*m_pfnBlockGet)(pItem + 1, pvContext);
  170. }
  171. return (pItem + 1);
  172. }
  173. #undef DPF_MODNAME
  174. #define DPF_MODNAME "CFixedPool::Release"
  175. VOID CFixedPool::Release(VOID* pvItem)
  176. {
  177. FIXED_POOL_ITEM* pItem;
  178. DNASSERT(m_fInitialized == TRUE);
  179. DNASSERT(pvItem != NULL);
  180. pItem = (FIXED_POOL_ITEM*)pvItem - 1;
  181. #ifdef DBG
  182. // Make sure the item comes from this pool.
  183. // If the item has already been released, pThisPool will be NULL.
  184. DNASSERT(pItem->pThisPool == this);
  185. #endif // DBG
  186. if (m_pfnBlockRelease != NULL)
  187. {
  188. (*m_pfnBlockRelease)(pvItem);
  189. }
  190. #ifdef DBG
  191. // Remove the item from the in use list.
  192. DNEnterCriticalSection(&m_csInUse);
  193. if (m_pInUseElements == &pItem->slist)
  194. {
  195. // Easy case, just reset m_pInUseElements to the next item in the list.
  196. m_pInUseElements = pItem->slist.Next;
  197. }
  198. else
  199. {
  200. DNSLIST_ENTRY* pslEntry;
  201. // We need to run the list and look for it
  202. pslEntry = m_pInUseElements;
  203. while (pslEntry != NULL)
  204. {
  205. if (pslEntry->Next == &pItem->slist)
  206. {
  207. // Found it, pull it out.
  208. pslEntry->Next = pItem->slist.Next;
  209. break;
  210. }
  211. pslEntry = pslEntry->Next;
  212. }
  213. }
  214. DNLeaveCriticalSection(&m_csInUse);
  215. #endif // DBG
  216. DNASSERT(m_lInUse != 0);
  217. InterlockedDecrement(&m_lInUse);
  218. DNInterlockedPushEntrySList(&m_slAvailableElements, &pItem->slist);
  219. }
  220. #undef DPF_MODNAME
  221. #define DPF_MODNAME "CFixedPool::GetInUseCount"
  222. DWORD CFixedPool::GetInUseCount( void )
  223. {
  224. DNASSERT(m_fInitialized == TRUE);
  225. return m_lInUse;
  226. }
  227. #ifdef DBG
  228. #undef DPF_MODNAME
  229. #define DPF_MODNAME "CFixedPool::DumpLeaks"
  230. VOID CFixedPool::DumpLeaks()
  231. {
  232. // NOTE: It is important that this be a separate function because it consumes so much stack space.
  233. FIXED_POOL_ITEM* pItem;
  234. DNSLIST_ENTRY* pslEntry;
  235. TCHAR szCallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
  236. // Report any leaked items
  237. if(m_lAllocated)
  238. {
  239. DNASSERT(m_lInUse == m_lAllocated);
  240. DNASSERT(m_pInUseElements != NULL);
  241. DPFX(DPFPREP, 0, "(%p) Pool leaking %d items", this, m_lAllocated);
  242. pslEntry = m_pInUseElements;
  243. while(pslEntry != NULL)
  244. {
  245. pItem = CONTAINING_RECORD(pslEntry, FIXED_POOL_ITEM, slist);
  246. pItem->callstack.GetCallStackString( szCallStackBuffer );
  247. DPFX(DPFPREP, 0, "(%p) Pool item leaked at address %p (user pointer: %p)\n%s", this, pItem, pItem + 1, szCallStackBuffer );
  248. pslEntry = pslEntry->Next;
  249. }
  250. DNASSERT(0);
  251. }
  252. else
  253. {
  254. DNASSERT(m_pInUseElements == NULL);
  255. DNASSERT(m_lInUse == 0);
  256. }
  257. }
  258. #endif // DBG