4 * Copyright 2001 Silicon Metrics, Inc.
6 * Permission to use, copy, modify, and distribute this software and
7 * its documentation for any purpose and without fee is hereby
8 * granted, provided that the above copyright notice appear in all
9 * copies and that both that the copyright notice and warranty
10 * disclaimer appear in supporting documentation, and that the names
11 * of Lucent Technologies any of their entities not be used in
12 * advertising or publicity pertaining to distribution of the software
13 * without specific, written prior permission.
15 * Silicon Metrics disclaims all warranties with regard to this
16 * software, including all implied warranties of merchantability and
17 * fitness. In no event shall Lucent Technologies be liable for any
18 * special, indirect or consequential damages or any damages
19 * whatsoever resulting from loss of use, data or profits, whether in
20 * an action of contract, negligence or other tortuous action, arising
21 * out of or in connection with the use or performance of this
31 * Implements a pool memory allocator.
33 * + It's faster allocating memory since malloc/free are called
34 * only a fraction of the normal times. Fixed size items can
35 * be reused without deallocating/reallocating memory.
36 * + You don't have the extra 8-16 byte overhead per malloc.
37 * - Memory is freed only when the entire pool is destroyed.
38 * - Memory is allocated in chunks. More memory is allocated
40 * 0 Depending upon allocation/deallocation patterns, locality
41 * may be improved or degraded.
43 * The pool is a chain of malloc'ed blocks.
45 * +---------+ +---------+ +---------+
46 * NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr
47 * |---------| |---------| |---------|
48 * | chunk1 | | chunk2 | | chunk3 |
55 * Each chunk contains an integral number of fixed size items.
56 * The number of items doubles until a maximum size is reached
57 * (each subsequent new chunk will be the maximum). Chunks
58 * are allocated only when needed (no more space is available
61 * The chain of blocks is only freed when the entire pool is
64 * A freelist of unused items also maintained. Each freed item
65 * is prepended to a free list. Before allocating new chunks
66 * the freelist is examined to see if an unused items exist.
68 * chunk1 chunk2 chunk3
69 * +---------+ +---------+ +---------+
70 * NULL<-| unused | | | | |
71 * +----^----+ +---------+ +---------+
72 * | unused |<-| unused |<-| unused |
73 * +---------+ +---------+ +----^----+
75 * +---------+ | | +----^----+
77 * +---------+ +----|----+
78 * | usused |<- freePtr
82 #define POOL_MAX_CHUNK_SIZE ((1<<16) - sizeof(Blt_PoolChain))
86 (((size_t)a + (sizeof(void *) - 1)) & (~(sizeof(void *) - 1)))
89 static Blt_PoolAllocProc VariablePoolAllocItem;
90 static Blt_PoolFreeProc VariablePoolFreeItem;
91 static Blt_PoolAllocProc FixedPoolAllocItem;
92 static Blt_PoolFreeProc FixedPoolFreeItem;
93 static Blt_PoolAllocProc StringPoolAllocItem;
94 static Blt_PoolFreeProc StringPoolFreeItem;
97 *----------------------------------------------------------------------
99 * VariablePoolAllocItem --
101 * Returns a new item. First check if there is any more space
102 * left in the current chunk. If there isn't then next check
103 * the free list for unused items. Finally allocate a new
104 * chunk and return its first item.
107 * Returns a new (possible reused) item.
110 * A new memory chunk may be allocated.
112 *----------------------------------------------------------------------
115 VariablePoolAllocItem(poolPtr, size)
116 struct Blt_PoolStruct *poolPtr;
117 size_t size; /* Number of bytes to allocate. */
119 Blt_PoolChain *chainPtr;
123 if (size >= POOL_MAX_CHUNK_SIZE) {
125 * Handle oversized requests by allocating a chunk to hold the
126 * single item and immediately placing it into the in-use list.
128 chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + size);
129 if (poolPtr->headPtr == NULL) {
130 poolPtr->headPtr = chainPtr;
132 chainPtr->nextPtr = poolPtr->headPtr->nextPtr;
133 poolPtr->headPtr->nextPtr = chainPtr;
135 memPtr = (void *)chainPtr;
137 if (poolPtr->bytesLeft >= size) {
138 poolPtr->bytesLeft -= size;
139 memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
141 poolPtr->waste += poolPtr->bytesLeft;
142 /* Create a new block of items and prepend it to the in-use list */
143 poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE;
144 /* Allocate the requested chunk size, plus the header */
145 chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + poolPtr->bytesLeft);
146 chainPtr->nextPtr = poolPtr->headPtr;
147 poolPtr->headPtr = chainPtr;
148 /* Peel off a new item. */
149 poolPtr->bytesLeft -= size;
150 memPtr = (char *)(chainPtr + 1) + poolPtr->bytesLeft;
157 *----------------------------------------------------------------------
159 * VariablePoolFreeItem --
161 * Placeholder for freeProc routine. The pool memory is
162 * not reclaimed or freed until the entire pool is released.
167 *----------------------------------------------------------------------
171 VariablePoolFreeItem(poolPtr, item)
172 struct Blt_PoolStruct *poolPtr;
179 *----------------------------------------------------------------------
181 * StringPoolAllocItem --
183 * Returns a new item. First check if there is any more space
184 * left in the current chunk. If there isn't then next check
185 * the free list for unused items. Finally allocate a new
186 * chunk and return its first item.
189 * Returns a new (possible reused) item.
192 * A new memory chunk may be allocated.
194 *----------------------------------------------------------------------
197 StringPoolAllocItem(poolPtr, size)
198 struct Blt_PoolStruct *poolPtr;
199 size_t size; /* Number of bytes to allocate. */
201 Blt_PoolChain *chainPtr;
204 if (size >= POOL_MAX_CHUNK_SIZE) {
206 * Handle oversized requests by allocating a chunk to hold the
207 * single item and immediately placing it into the in-use list.
209 chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + size);
210 if (poolPtr->headPtr == NULL) {
211 poolPtr->headPtr = chainPtr;
213 chainPtr->nextPtr = poolPtr->headPtr->nextPtr;
214 poolPtr->headPtr->nextPtr = chainPtr;
216 memPtr = (void *)chainPtr;
218 if (poolPtr->bytesLeft >= size) {
219 poolPtr->bytesLeft -= size;
220 memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
222 poolPtr->waste += poolPtr->bytesLeft;
223 /* Create a new block of items and prepend it to the
225 poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE;
226 /* Allocate the requested chunk size, plus the header */
227 chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + poolPtr->bytesLeft);
228 chainPtr->nextPtr = poolPtr->headPtr;
229 poolPtr->headPtr = chainPtr;
230 /* Peel off a new item. */
231 poolPtr->bytesLeft -= size;
232 memPtr = (char *)(chainPtr + 1) + poolPtr->bytesLeft;
239 *----------------------------------------------------------------------
241 * StringPoolFreeItem --
243 * Placeholder for freeProc routine. String pool memory is
244 * not reclaimed or freed until the entire pool is released.
249 *----------------------------------------------------------------------
253 StringPoolFreeItem(poolPtr, item)
254 struct Blt_PoolStruct *poolPtr;
261 * The fixed size pool is a chain of malloc'ed blocks.
263 * +---------+ +---------+ +---------+
264 * NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr
265 * |---------| |---------| |---------|
266 * | chunk1 | | chunk2 | | chunk3 |
267 * +---------+ | | | |
273 * Each chunk contains an integral number of fixed size items.
274 * The number of items doubles until a maximum size is reached
275 * (each subsequent new chunk will be the maximum). Chunks
276 * are allocated only when needed (no more space is available
277 * in the last chunk).
279 * The chain of blocks is only freed when the entire pool is
282 * A freelist of unused items also maintained. Each freed item
283 * is prepended to a free list. Before allocating new chunks
284 * the freelist is examined to see if an unused items exist.
286 * chunk1 chunk2 chunk3
287 * +---------+ +---------+ +---------+
288 * NULL<-| unused | | | | |
289 * +----^----+ +---------+ +---------+
290 * | unused |<-| unused |<-| unused |
291 * +---------+ +---------+ +----^----+
293 * +---------+ | | +----^----+
295 * +---------+ +----|----+
296 * | usused |<- freePtr
301 *----------------------------------------------------------------------
303 * FixedPoolFreeItem --
305 * Returns a new item. First check if there is any more space
306 * left in the current chunk. If there isn't then next check
307 * the free list for unused items. Finally allocate a new
308 * chunk and return its first item.
311 * Returns a new (possible reused) item.
314 * A new memory chunk may be allocated.
316 *----------------------------------------------------------------------
319 FixedPoolAllocItem(poolPtr, size)
320 struct Blt_PoolStruct *poolPtr;
323 Blt_PoolChain *chainPtr;
327 if (poolPtr->itemSize == 0) {
328 poolPtr->itemSize = size;
330 assert(size == poolPtr->itemSize);
332 if (poolPtr->bytesLeft > 0) {
333 poolPtr->bytesLeft -= poolPtr->itemSize;
334 newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
335 } else if (poolPtr->freePtr != NULL) { /* Reuse from the free list. */
336 /* Reuse items on the free list */
337 chainPtr = poolPtr->freePtr;
338 poolPtr->freePtr = chainPtr->nextPtr;
339 newPtr = (void *)chainPtr;
340 } else { /* Allocate another block. */
342 /* Create a new block of items and prepend it to the in-use list */
343 poolPtr->bytesLeft = poolPtr->itemSize * (1 << poolPtr->poolSize);
344 if (poolPtr->bytesLeft < POOL_MAX_CHUNK_SIZE) {
345 poolPtr->poolSize++; /* Keep doubling the size of the new
346 * chunk up to a maximum size. */
348 /* Allocate the requested chunk size, plus the header */
349 chainPtr = Blt_Malloc(sizeof(Blt_PoolChain) + poolPtr->bytesLeft);
350 chainPtr->nextPtr = poolPtr->headPtr;
351 poolPtr->headPtr = chainPtr;
353 /* Peel off a new item. */
354 poolPtr->bytesLeft -= poolPtr->itemSize;
355 newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
361 *----------------------------------------------------------------------
363 * FixedPoolFreeItem --
365 * Frees an item. The actual memory is not freed. The item
366 * instead is prepended to a freelist where it may be reclaimed
373 * Item is placed on the pool's free list.
375 *----------------------------------------------------------------------
378 FixedPoolFreeItem(poolPtr, item)
379 struct Blt_PoolStruct *poolPtr;
382 Blt_PoolChain *chainPtr = (Blt_PoolChain *)item;
384 /* Prepend the newly deallocated item to the free list. */
385 chainPtr->nextPtr = poolPtr->freePtr;
386 poolPtr->freePtr = chainPtr;
390 *----------------------------------------------------------------------
394 * Creates a new memory pool for fixed-size/variable-size/string
398 * Returns a pointer to the newly allocated pool.
400 *----------------------------------------------------------------------
407 struct Blt_PoolStruct *poolPtr;
409 poolPtr = Blt_Malloc(sizeof(struct Blt_PoolStruct));
411 case BLT_VARIABLE_SIZE_ITEMS:
412 poolPtr->allocProc = VariablePoolAllocItem;
413 poolPtr->freeProc = VariablePoolFreeItem;
415 case BLT_FIXED_SIZE_ITEMS:
416 poolPtr->allocProc = FixedPoolAllocItem;
417 poolPtr->freeProc = FixedPoolFreeItem;
419 case BLT_STRING_ITEMS:
420 poolPtr->allocProc = StringPoolAllocItem;
421 poolPtr->freeProc = StringPoolFreeItem;
424 poolPtr->headPtr = poolPtr->freePtr = NULL;
425 poolPtr->waste = poolPtr->bytesLeft = 0;
426 poolPtr->poolSize = poolPtr->itemSize = 0;
431 *----------------------------------------------------------------------
435 * Destroys the given memory pool. The chain of allocated blocks
436 * are freed. The is the only time that memory is actually freed.
442 * All memory used by the pool is freed.
444 *----------------------------------------------------------------------
447 Blt_PoolDestroy(poolPtr)
448 struct Blt_PoolStruct *poolPtr;
450 register Blt_PoolChain *chainPtr, *nextPtr;
452 for (chainPtr = poolPtr->headPtr; chainPtr != NULL; chainPtr = nextPtr) {
453 nextPtr = chainPtr->nextPtr;