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.

449 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. bufpool.c
  5. Abstract:
  6. Generic Buffer Pool Manager.
  7. Author:
  8. Mike Massa (mikemas) April 5, 1996
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 04-05-96 created
  13. Notes:
  14. Buffer Pools provide a mechanism for managing caches of fixed size
  15. structures which are frequently allocated/deallocated.
  16. --*/
  17. #include "clusrtlp.h"
  18. //
  19. // Pool of generic buffers
  20. //
  21. typedef struct _CLRTL_BUFFER_POOL {
  22. DWORD PoolSignature;
  23. DWORD BufferSize;
  24. SINGLE_LIST_ENTRY FreeList;
  25. DWORD MaximumCached;
  26. DWORD CurrentCached;
  27. DWORD MaximumAllocated;
  28. DWORD ReferenceCount;
  29. CLRTL_BUFFER_CONSTRUCTOR Constructor;
  30. CLRTL_BUFFER_DESTRUCTOR Destructor;
  31. CRITICAL_SECTION Lock;
  32. } CLRTL_BUFFER_POOL;
  33. //
  34. // Header for each allocated buffer
  35. //
  36. typedef struct {
  37. SINGLE_LIST_ENTRY Linkage;
  38. PCLRTL_BUFFER_POOL Pool;
  39. } BUFFER_HEADER, *PBUFFER_HEADER;
  40. #define BP_SIG 'loop'
  41. #define ASSERT_BP_SIG(pool) CL_ASSERT((pool)->PoolSignature == BP_SIG)
  42. //
  43. // Macros
  44. //
  45. //
  46. #define BpAllocateMemory(size) LocalAlloc(LMEM_FIXED, (size))
  47. #define BpFreeMemory(buf) LocalFree(buf)
  48. #define BpAcquirePoolLock(Pool) EnterCriticalSection(&((Pool)->Lock))
  49. #define BpReleasePoolLock(Pool) LeaveCriticalSection(&((Pool)->Lock))
  50. //
  51. // Public Functions
  52. //
  53. PCLRTL_BUFFER_POOL
  54. ClRtlCreateBufferPool(
  55. IN DWORD BufferSize,
  56. IN DWORD MaximumCached,
  57. IN DWORD MaximumAllocated,
  58. IN CLRTL_BUFFER_CONSTRUCTOR Constructor, OPTIONAL
  59. IN CLRTL_BUFFER_DESTRUCTOR Destructor OPTIONAL
  60. )
  61. /*++
  62. Routine Description:
  63. Creates a pool from which fixed-size buffers may be allocated.
  64. Arguments:
  65. BufferSize - Size of the buffers managed by the pool.
  66. MaximumCached - The maximum number of buffers to cache in the pool.
  67. Must be less than or equal to MaximumAllocated.
  68. MaximumAllocated - The maximum number of buffers to allocate from
  69. system memory. Must be less than or equal to
  70. CLRTL_MAX_POOL_BUFFERS.
  71. Constructor - An optional routine to be called when a new buffer
  72. is allocated from system memory. May be NULL
  73. Destructor - An optional routine to be called when a buffer
  74. is returned to system memory. May be NULL.
  75. Return Value:
  76. A pointer to the created buffer pool or NULL on error.
  77. Extended error information is available from GetLastError().
  78. --*/
  79. {
  80. PCLRTL_BUFFER_POOL pool;
  81. if ( (MaximumAllocated > CLRTL_MAX_POOL_BUFFERS) ||
  82. (MaximumCached > MaximumAllocated)
  83. )
  84. {
  85. SetLastError(ERROR_INVALID_PARAMETER);
  86. return(NULL);
  87. }
  88. pool = BpAllocateMemory(sizeof(CLRTL_BUFFER_POOL));
  89. if (pool != NULL) {
  90. InitializeCriticalSection(&(pool->Lock));
  91. pool->PoolSignature = BP_SIG;
  92. pool->BufferSize = sizeof(BUFFER_HEADER) + BufferSize;
  93. pool->FreeList.Next = NULL;
  94. pool->MaximumCached = MaximumCached;
  95. pool->CurrentCached = 0;
  96. pool->MaximumAllocated = MaximumAllocated + 1;
  97. pool->ReferenceCount = 1;
  98. pool->Constructor = Constructor;
  99. pool->Destructor = Destructor;
  100. }
  101. else {
  102. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  103. }
  104. return(pool);
  105. }
  106. VOID
  107. ClRtlDestroyBufferPool(
  108. IN PCLRTL_BUFFER_POOL Pool
  109. )
  110. /*++
  111. Routine Description:
  112. Destroys a previously created buffer pool.
  113. Arguments:
  114. Pool - A pointer to the pool to destroy.
  115. Return Value:
  116. None.
  117. Notes:
  118. The pool will not actually be destroyed until all outstanding
  119. buffers have been returned. Each outstanding buffer is effectively
  120. a reference on the pool.
  121. --*/
  122. {
  123. SINGLE_LIST_ENTRY deleteList;
  124. CLRTL_BUFFER_DESTRUCTOR destructor;
  125. PSINGLE_LIST_ENTRY item;
  126. PBUFFER_HEADER header;
  127. BOOLEAN freePool;
  128. deleteList.Next = NULL;
  129. ASSERT_BP_SIG(Pool);
  130. BpAcquirePoolLock(Pool);
  131. CL_ASSERT(Pool->ReferenceCount != 0);
  132. Pool->ReferenceCount--; // Remove initial reference.
  133. destructor = Pool->Destructor;
  134. //
  135. // Free all cached buffers
  136. //
  137. item = PopEntryList(&(Pool->FreeList));
  138. while (item != NULL) {
  139. CL_ASSERT(Pool->ReferenceCount != 0);
  140. PushEntryList(&deleteList, item);
  141. Pool->ReferenceCount--;
  142. item = PopEntryList(&(Pool->FreeList));
  143. }
  144. if (Pool->ReferenceCount == 0) {
  145. BpReleasePoolLock(Pool);
  146. DeleteCriticalSection(&(Pool->Lock));
  147. BpFreeMemory(Pool);
  148. }
  149. else {
  150. //
  151. // Pool destruction is deferred until all buffers have been freed.
  152. //
  153. Pool->CurrentCached = 0;
  154. Pool->MaximumCached = 0;
  155. BpReleasePoolLock(Pool);
  156. }
  157. item = PopEntryList(&deleteList);
  158. while (item != NULL) {
  159. header = CONTAINING_RECORD(
  160. item,
  161. BUFFER_HEADER,
  162. Linkage
  163. );
  164. if (destructor != NULL) {
  165. (*destructor)(header+1);
  166. }
  167. BpFreeMemory(header);
  168. item = PopEntryList(&deleteList);
  169. }
  170. return;
  171. }
  172. PVOID
  173. ClRtlAllocateBuffer(
  174. IN PCLRTL_BUFFER_POOL Pool
  175. )
  176. /*++
  177. Routine Description:
  178. Allocates a buffer from a previously created buffer pool.
  179. Arguments:
  180. Pool - A pointer to the pool from which to allocate the buffer.
  181. Return Value:
  182. A pointer to the allocated buffer if the routine was successfull.
  183. NULL if the routine failed. Extended error information is available
  184. by calling GetLastError().
  185. --*/
  186. {
  187. //
  188. // turn this fancy stuff off until it works.
  189. //
  190. #if 0
  191. PSINGLE_LIST_ENTRY item;
  192. PBUFFER_HEADER header;
  193. PVOID buffer;
  194. DWORD status;
  195. ASSERT_BP_SIG(Pool);
  196. BpAcquirePoolLock(Pool);
  197. //
  198. // First, check the cache.
  199. //
  200. item = PopEntryList(&(Pool->FreeList));
  201. if (item != NULL) {
  202. CL_ASSERT(Pool->CurrentCached != 0);
  203. Pool->CurrentCached--;
  204. BpReleasePoolLock(Pool);
  205. header = CONTAINING_RECORD(
  206. item,
  207. BUFFER_HEADER,
  208. Linkage
  209. );
  210. return(header+1);
  211. }
  212. //
  213. // Need to allocate a fresh buffer from system memory.
  214. //
  215. if (Pool->ReferenceCount < Pool->MaximumAllocated) {
  216. //
  217. // This is equivalent to a reference on the Pool.
  218. //
  219. Pool->ReferenceCount++;
  220. BpReleasePoolLock(Pool);
  221. header = BpAllocateMemory(Pool->BufferSize);
  222. if (header != NULL) {
  223. header->Pool = Pool;
  224. buffer = header+1;
  225. if (Pool->Constructor == NULL) {
  226. return(buffer);
  227. }
  228. status = (*(Pool->Constructor))(buffer);
  229. if (status == ERROR_SUCCESS) {
  230. return(buffer);
  231. }
  232. SetLastError(status);
  233. //
  234. // The constructor failed.
  235. //
  236. BpFreeMemory(header);
  237. }
  238. else {
  239. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  240. }
  241. //
  242. // Failed - undo the reference.
  243. //
  244. BpAcquirePoolLock(Pool);
  245. Pool->ReferenceCount--;
  246. }
  247. else {
  248. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  249. }
  250. BpReleasePoolLock(Pool);
  251. return(NULL);
  252. #else
  253. return(LocalAlloc(LMEM_FIXED, Pool->BufferSize));
  254. #endif
  255. }
  256. VOID
  257. ClRtlFreeBuffer(
  258. PVOID Buffer
  259. )
  260. /*++
  261. Routine Description:
  262. Frees a buffer back to its owning pool.
  263. Arguments:
  264. Buffer - The buffer to free.
  265. Return Value:
  266. None.
  267. --*/
  268. {
  269. //
  270. // turn this fancy stuff off until it works.
  271. //
  272. #if 0
  273. PBUFFER_HEADER header;
  274. PCLRTL_BUFFER_POOL pool;
  275. CLRTL_BUFFER_DESTRUCTOR destructor;
  276. header = ((PBUFFER_HEADER) Buffer) - 1;
  277. pool = header->Pool;
  278. ASSERT_BP_SIG(pool);
  279. BpAcquirePoolLock(pool);
  280. if (pool->CurrentCached < pool->MaximumCached) {
  281. //
  282. // Return to free list
  283. //
  284. PushEntryList(
  285. &(pool->FreeList),
  286. (PSINGLE_LIST_ENTRY) &(header->Linkage)
  287. );
  288. pool->CurrentCached++;
  289. BpReleasePoolLock(pool);
  290. return;
  291. }
  292. destructor = pool->Destructor;
  293. CL_ASSERT(pool->ReferenceCount != 0);
  294. if (--(pool->ReferenceCount) != 0) {
  295. BpReleasePoolLock(pool);
  296. if (destructor) {
  297. (*destructor)(Buffer);
  298. }
  299. BpFreeMemory(header);
  300. return;
  301. }
  302. CL_ASSERT(pool->CurrentCached == 0);
  303. BpReleasePoolLock(pool);
  304. DeleteCriticalSection(&(pool->Lock));
  305. BpFreeMemory(pool);
  306. if (destructor) {
  307. (*destructor)(Buffer);
  308. }
  309. BpFreeMemory(header);
  310. return;
  311. #else
  312. LocalFree(Buffer);
  313. #endif
  314. }