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.

279 lines
6.8 KiB

  1. // Copyright (c) 1998 Microsoft Corporation
  2. //
  3. // TPool.h
  4. //
  5. // Template pool memory manager. Efficiently manage requests for many of the same (small) object.
  6. // Named after t'Pool, the Vulcan programmer who invented the technique.
  7. //
  8. #ifndef _TPOOL_H_
  9. #define _TPOOL_H_
  10. #include "debug.h"
  11. #define POOL_DEFAULT_BYTE_PER_BLOCK 4096
  12. #define MIN_ITEMS_PER_BLOCK 4
  13. ///////////////////////////////////////////////////////////////////////////////
  14. //
  15. // CPool
  16. //
  17. // A simple memory manager that efficiently handles many objects of the same
  18. // size by allocating blocks containing multiple objects at once.
  19. //
  20. //
  21. template<class contained> class CPool
  22. {
  23. public:
  24. CPool(int nApproxBytesPerBlock = POOL_DEFAULT_BYTE_PER_BLOCK);
  25. ~CPool();
  26. contained *Alloc();
  27. void Free(contained* pToFree);
  28. private:
  29. union CPoolNode
  30. {
  31. CPoolNode *pNext;
  32. contained c;
  33. };
  34. class CPoolBlock
  35. {
  36. public:
  37. CPoolBlock *pNext;
  38. CPoolNode *pObjects;
  39. };
  40. int nItemsPerBlock; // Based on bytes per block
  41. int nAllocatedBlocks; // # allocated blocks
  42. CPoolBlock *pAllocatedBlocks; // list of allocated blocks
  43. int nFreeList; // # nodes in free list
  44. CPoolNode *pFreeList; // free list
  45. private:
  46. bool RefillFreeList();
  47. #ifdef DBG
  48. bool IsPoolNode(CPoolNode *pNode);
  49. bool IsInFreeList(CPoolNode *pNode);
  50. #endif
  51. };
  52. ///////////////////////////////////////////////////////////////////////////////
  53. //
  54. // CPool::CPool
  55. //
  56. // Figure out the number of contained objects per block based on the requested
  57. // approximate block size. Initialize the free list to contain one block's
  58. // worth of objects.
  59. //
  60. //
  61. template<class contained> CPool<contained>::CPool(int nApproxBytesPerBlock)
  62. {
  63. // Figure out how many items per block and cheat if too small
  64. //
  65. nItemsPerBlock = nApproxBytesPerBlock / sizeof(CPoolNode);
  66. if (nItemsPerBlock < MIN_ITEMS_PER_BLOCK)
  67. {
  68. nItemsPerBlock = MIN_ITEMS_PER_BLOCK;
  69. }
  70. nAllocatedBlocks = 0;
  71. pAllocatedBlocks = NULL;
  72. nFreeList = 0;
  73. pFreeList = NULL;
  74. // Fill up with some items ahead of time
  75. //
  76. RefillFreeList();
  77. }
  78. ///////////////////////////////////////////////////////////////////////////////
  79. //
  80. // CPool::~CPool
  81. //
  82. // Free up all allocated blocks. There should be no outstanding blocks
  83. // allocated at this point.
  84. //
  85. //
  86. template<class contained> CPool<contained>::~CPool()
  87. {
  88. #ifdef DBG
  89. if (nFreeList < nAllocatedBlocks * nItemsPerBlock)
  90. {
  91. Trace(0, "CPool::~Cpool: Warning: free'ing with outstanding objects allocated.\n");
  92. }
  93. #endif
  94. // Clean up all allocated blocks and contained objects.
  95. //
  96. while (pAllocatedBlocks)
  97. {
  98. CPoolBlock *pNext = pAllocatedBlocks->pNext;
  99. delete[] pAllocatedBlocks->pObjects;
  100. delete pAllocatedBlocks;
  101. pAllocatedBlocks = pNext;
  102. }
  103. }
  104. ///////////////////////////////////////////////////////////////////////////////
  105. //
  106. // CPool::Alloc
  107. //
  108. // Attempt to allocate a contained object and return NULL if out of memory.
  109. // If the free list is empty then allocate another block.
  110. //
  111. //
  112. template<class contained> contained *CPool<contained>::Alloc()
  113. {
  114. if (pFreeList == NULL)
  115. {
  116. if (!RefillFreeList())
  117. {
  118. return false;
  119. }
  120. }
  121. nFreeList--;
  122. contained *pAlloc = (contained*)pFreeList;
  123. pFreeList = pFreeList->pNext;
  124. return pAlloc;
  125. }
  126. ///////////////////////////////////////////////////////////////////////////////
  127. //
  128. // CPool::Free
  129. //
  130. // Return a contained object to the free list. In the debug version make sure
  131. // the object was in fact allocated from this pool in the first place and that
  132. // it isn't already in the free list.
  133. //
  134. //
  135. template<class contained> void CPool<contained>::Free(contained *pToFree)
  136. {
  137. CPoolNode *pNode = (CPoolNode*)pToFree;
  138. #ifdef DBG
  139. if (!IsPoolNode(pNode))
  140. {
  141. Trace(0, "CPool::Free() Object %p is not a pool node; ignored.\n", pToFree);
  142. return;
  143. }
  144. if (IsInFreeList(pNode))
  145. {
  146. Trace(0, "CPool::Free() Object %p is already in the free list; ignored.\n", pToFree);
  147. return;
  148. }
  149. #endif
  150. nFreeList++;
  151. pNode->pNext = pFreeList;
  152. pFreeList = pNode;
  153. }
  154. ///////////////////////////////////////////////////////////////////////////////
  155. //
  156. // CPool::RefillFreeList
  157. //
  158. // Add one block's worth of contained objects to the free list, tracking the
  159. // allocated memory so we can free it later.
  160. //
  161. //
  162. template<class contained> bool CPool<contained>::RefillFreeList()
  163. {
  164. // Allocate a new block and the actual block of objects
  165. //
  166. CPoolBlock *pNewBlock = new CPoolBlock;
  167. if (pNewBlock == NULL)
  168. {
  169. return false;
  170. }
  171. pNewBlock->pObjects = new CPoolNode[nItemsPerBlock];
  172. if (pNewBlock->pObjects == NULL)
  173. {
  174. delete pNewBlock;
  175. return false;
  176. }
  177. // Link the block and objects into the right places. First link the new block
  178. // into the list of allocated blocks.
  179. //
  180. pNewBlock->pNext = pAllocatedBlocks;
  181. pAllocatedBlocks = pNewBlock;
  182. // Link all the contained object nodes into the free list.
  183. //
  184. CPoolNode *pFirstNode = &pNewBlock->pObjects[0];
  185. CPoolNode *pLastNode = &pNewBlock->pObjects[nItemsPerBlock - 1];
  186. for (CPoolNode *pNode = pFirstNode; pNode < pLastNode; pNode++)
  187. {
  188. pNode->pNext = pNode + 1;
  189. }
  190. pLastNode->pNext = pFreeList;
  191. pFreeList = pFirstNode;
  192. nFreeList += nItemsPerBlock;
  193. nAllocatedBlocks++;
  194. return true;
  195. }
  196. #ifdef DBG
  197. ///////////////////////////////////////////////////////////////////////////////
  198. //
  199. // CPool::IsPoolNode (debug)
  200. //
  201. // Verify that the passed pointer is a pointer to a pool node by walking the list
  202. // of allocated blocks.
  203. //
  204. //
  205. template<class contained> bool CPool<contained>::IsPoolNode(CPoolNode *pTest)
  206. {
  207. for (CPoolBlock *pBlock = pAllocatedBlocks; pBlock; pBlock = pBlock->pNext)
  208. {
  209. CPoolNode *pFirstNode = &pBlock->pObjects[0];
  210. CPoolNode *pLastNode = &pBlock->pObjects[nItemsPerBlock - 1];
  211. for (CPoolNode *pNode = pFirstNode; pNode <= pLastNode; pNode++)
  212. {
  213. if (pNode == pTest)
  214. {
  215. return true;
  216. }
  217. }
  218. }
  219. return false;
  220. }
  221. ///////////////////////////////////////////////////////////////////////////////
  222. //
  223. // CPool::IsInFreeList (debug)
  224. //
  225. // Verify that the passed pointer points to a node that is already in the free
  226. // list.
  227. //
  228. //
  229. template<class contained> bool CPool<contained>::IsInFreeList(CPoolNode *pTest)
  230. {
  231. for (CPoolNode *pNode = pFreeList; pNode; pNode = pNode->pNext)
  232. {
  233. if (pTest == pNode)
  234. {
  235. return true;
  236. }
  237. }
  238. return false;
  239. }
  240. #endif // DBG
  241. #endif // _TPOOL_H_