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.

310 lines
6.0 KiB

  1. /*++
  2. Copyright (c) 1993-1999 Microsoft Corporation
  3. Module Name:
  4. pool.cpp
  5. Abstract:
  6. Fixed size memory allocator.
  7. Author:
  8. Bill Bolosky [bolosky] 1993
  9. Revision History:
  10. --*/
  11. #include "sibp.h"
  12. struct PoolEntry {
  13. void *object;
  14. struct PoolEntry *next;
  15. };
  16. struct PoolBlob {
  17. struct PoolBlob *next;
  18. void *data;
  19. };
  20. Pool::Pool(
  21. unsigned objectSize,
  22. void *(*allocator)(unsigned),
  23. unsigned blobSize,
  24. void (*destructor)(void *))
  25. {
  26. assert(objectSize > 0);
  27. assert(!destructor || allocator); // Can't have a destructor without an allocator. Allocator w/o destructor leaks objects on pool destruct.
  28. this->countAllocator = allocator;
  29. this->singleAllocator = NULL;
  30. this->destructor = destructor;
  31. this->objectSize = objectSize;
  32. entries = NULL;
  33. freeEntries = NULL;
  34. entriesBlobHead = NULL;
  35. objectsBlobHead = NULL;
  36. entriesPerBlob = blobSize / sizeof(PoolEntry);
  37. assert(entriesPerBlob > 0);
  38. objectsPerBlob = blobSize / objectSize;
  39. if (!objectsPerBlob) {
  40. objectsPerBlob = 1;
  41. }
  42. allocations = 0;
  43. frees = 0;
  44. news = 0;
  45. numFree = 0;
  46. }
  47. // This version of the pool constructor uses the old kind of allocator function that only returns one object. Object blobs have one object,
  48. // and the blob size for entry blobs is smaller so that we have finer grain memory allocation.
  49. Pool::Pool(
  50. unsigned objectSize,
  51. void *(*allocator)(void))
  52. {
  53. assert(objectSize > 0);
  54. assert(!destructor || allocator); // Can't have a destructor without an allocator; allocator w/o destructor leaks objects on pool destruct
  55. this->singleAllocator = allocator;
  56. this->countAllocator = NULL;
  57. this->destructor = NULL;
  58. this->objectSize = objectSize;
  59. entries = NULL;
  60. freeEntries = NULL;
  61. entriesBlobHead = NULL;
  62. objectsBlobHead = NULL;
  63. unsigned blobSize = 1024 - 50; // Our default allocation size; we leave the 50 byte headroom for the underlying allocator
  64. entriesPerBlob = blobSize / sizeof(PoolEntry);
  65. assert(entriesPerBlob > 0);
  66. objectsPerBlob = 1;
  67. allocations = 0;
  68. frees = 0;
  69. news = 0;
  70. numFree = 0;
  71. }
  72. Pool::~Pool(void)
  73. {
  74. // Just delete the blob lists. All objects that have been allocated from this pool will be destroyed.
  75. while (entriesBlobHead) {
  76. PoolBlob *blob = entriesBlobHead;
  77. assert(blob->data);
  78. delete [] blob->data;
  79. entriesBlobHead = blob->next;
  80. delete blob;
  81. }
  82. while (objectsBlobHead) {
  83. PoolBlob *blob = objectsBlobHead;
  84. assert(blob->data);
  85. if (destructor) {
  86. (*destructor)(blob->data);
  87. } else if (!singleAllocator && !countAllocator) {
  88. delete [] blob->data;
  89. } // else leak the objects
  90. objectsBlobHead = blob->next;
  91. delete blob;
  92. }
  93. }
  94. void
  95. Pool::allocateMoreObjects(void)
  96. {
  97. assert(objectsPerBlob);
  98. PoolBlob *blob = new PoolBlob;
  99. if (!blob) {
  100. return;
  101. }
  102. if (countAllocator) {
  103. blob->data = (*countAllocator)(objectsPerBlob);
  104. } else if (singleAllocator) {
  105. assert(objectsPerBlob == 1);
  106. blob->data = (*singleAllocator)();
  107. } else {
  108. blob->data = (void *)new char[objectSize * objectsPerBlob];
  109. }
  110. if (!blob->data) {
  111. delete blob;
  112. return;
  113. }
  114. blob->next = objectsBlobHead;
  115. objectsBlobHead = blob;
  116. // Now put them on the free list.
  117. for (unsigned i = 0; i < objectsPerBlob; i++) {
  118. PoolEntry *entry = getEntry();
  119. if (!entry) {
  120. return; // This is kinda bogus, because it might leave some allocated objects unreachable.
  121. }
  122. entry->object = (void *)(((char *)blob->data) + i * objectSize);
  123. entry->next = entries;
  124. entries = entry;
  125. }
  126. news += objectsPerBlob;
  127. numFree += objectsPerBlob;
  128. }
  129. // Allocate entries until the free list is of size n (or until an allocation fails).
  130. void
  131. Pool::preAllocate(
  132. unsigned n)
  133. {
  134. assert(n);
  135. while (numFree < n) {
  136. unsigned oldNumFree = numFree;
  137. allocateMoreObjects();
  138. if (oldNumFree == numFree) {
  139. // We can't allocate more; punt
  140. return;
  141. }
  142. }
  143. }
  144. PoolEntry *
  145. Pool::getEntry(void)
  146. {
  147. PoolEntry *entry = NULL;
  148. if (freeEntries) {
  149. entry = freeEntries;
  150. freeEntries = entry->next;
  151. assert(entry->object == NULL);
  152. } else {
  153. // Allocate a new entry blob and fill it in.
  154. PoolBlob *blob = new PoolBlob;
  155. if (blob) {
  156. PoolEntry *blobEntries = new PoolEntry[entriesPerBlob];
  157. if (blobEntries) {
  158. blob->data = (void *)blobEntries;
  159. // Release all of the newly allocated entries except the first one, which we'll return.
  160. for (unsigned i = 1; i < entriesPerBlob; i++) {
  161. releaseEntry(&blobEntries[i]);
  162. }
  163. entry = &blobEntries[0];
  164. // Stick the new blob on the entries blob list.
  165. blob->next = entriesBlobHead;
  166. entriesBlobHead = blob;
  167. } else {
  168. // Give up; we couldn't get memory
  169. delete blob;
  170. }
  171. }
  172. }
  173. return(entry);
  174. }
  175. void
  176. Pool::releaseEntry(
  177. PoolEntry *entry)
  178. {
  179. assert(entry);
  180. entry->object = NULL;
  181. entry->next = freeEntries;
  182. freeEntries = entry;
  183. }
  184. void *
  185. Pool::allocate(void)
  186. {
  187. allocations++;
  188. assert((numFree == 0) == (entries == NULL));
  189. if (!entries) {
  190. allocateMoreObjects();
  191. }
  192. if (entries) {
  193. // We've got something
  194. struct PoolEntry *thisEntry = entries;
  195. entries = entries->next;
  196. void *object = thisEntry->object;
  197. assert(object);
  198. releaseEntry(thisEntry);
  199. assert(numFree);
  200. numFree--;
  201. return(object);
  202. } else {
  203. // Coudn't allocate more, we're out of memory.
  204. assert(numFree == 0);
  205. return NULL;
  206. }
  207. }
  208. void
  209. Pool::free(
  210. void *object)
  211. {
  212. assert(object);
  213. frees++;
  214. // No way to assert that this is the right kind (size) of object...
  215. // Get a PoolEntry.
  216. struct PoolEntry *entry = getEntry();
  217. if (!entry) {
  218. // We couldn't get an entry, so we can't add this object to the free list. Leak it.
  219. return;
  220. }
  221. numFree++;
  222. entry->object = object;
  223. entry->next = entries;
  224. entries = entry;
  225. }
  226. unsigned
  227. Pool::numAllocations(void)
  228. {
  229. return(allocations);
  230. }
  231. unsigned
  232. Pool::numFrees(void)
  233. {
  234. return(frees);
  235. }
  236. unsigned
  237. Pool::numNews(void)
  238. {
  239. return(news);
  240. }
  241. unsigned
  242. Pool::getObjectSize(void)
  243. {
  244. return(objectSize);
  245. }