source: branches/blt4/src/objects/RpPool.c @ 1897

Last change on this file since 1897 was 1270, checked in by dkearney, 15 years ago

rappture object updates, stuff i'm playing around with. the code is not functional but it compiles, and i dont want to loose this state as i continue to play. the configure scripts and makefiles should still be working properly.

File size: 15.0 KB
Line 
1/*
2 * bltPool.c --
3 *
4 * Copyright 2001 Silicon Metrics, Inc.
5 *
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.
14 *
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
22 * software.
23 */
24
25#include "RpInt.h"
26#include "RpPool.h"
27
28/*
29 * Rp_Pool --
30 *
31 *  Implements a pool memory allocator.
32 *
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
39 *      than used.
40 *    0 Depending upon allocation/deallocation patterns, locality
41 *      may be improved or degraded.
42 *
43 *      The pool is a chain of malloc'ed blocks.
44 *
45 *             +---------+  +---------+  +---------+
46 *       NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr
47 *             |---------|  |---------|  |---------|
48 *             | chunk1  |  | chunk2  |  | chunk3  |
49 *             +---------+  |         |  |         |
50 *                          +---------+  |         |
51 *                                       |         |
52 *                                       |         |
53 *                                       +---------+
54 *
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
59 *      in the last chunk).
60 *
61 *      The chain of blocks is only freed when the entire pool is
62 *      destroyed.
63 *
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.
67 *
68 *               chunk1       chunk2       chunk3
69 *            +---------+  +---------+  +---------+
70 *      NULL<-| unused  |  |         |  |         |
71 *            +----^----+  +---------+  +---------+
72 *            | unused  |<-| unused  |<-| unused  |
73 *            +---------+  +---------+  +----^----+
74 *            |         |  |         |  | unused  |
75 *            +---------+  |         |  +----^----+
76 *                         |         |  |    |    |
77 *                         +---------+  +----|----+
78 *                                      | usused  |<- freePtr
79 *                                      +---------+
80 */
81
82#define POOL_MAX_CHUNK_SIZE      ((1<<16) - sizeof(Rp_PoolChain))
83
84#ifndef ALIGN
85#define ALIGN(a) \
86    (((size_t)a + (sizeof(void *) - 1)) & (~(sizeof(void *) - 1)))
87#endif /* ALIGN */
88
89static Rp_PoolAllocProc VariablePoolAllocItem;
90static Rp_PoolFreeProc  VariablePoolFreeItem;
91static Rp_PoolAllocProc FixedPoolAllocItem;
92static Rp_PoolFreeProc  FixedPoolFreeItem;
93static Rp_PoolAllocProc StringPoolAllocItem;
94static Rp_PoolFreeProc  StringPoolFreeItem;
95
96/*
97 *----------------------------------------------------------------------
98 *
99 * VariablePoolAllocItem --
100 *
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.
105 *
106 * Results:
107 *      Returns a new (possible reused) item.
108 *
109 * Side Effects:
110 *      A new memory chunk may be allocated.
111 *
112 *----------------------------------------------------------------------
113 */
114static void *
115VariablePoolAllocItem(poolPtr, size)
116    struct Rp_PoolStruct *poolPtr;
117    size_t size;    /* Number of bytes to allocate. */
118{
119    Rp_PoolChain *chainPtr;
120    void *memPtr;
121
122    size = ALIGN(size);
123    if (size >= POOL_MAX_CHUNK_SIZE) {
124    /*
125     * Handle oversized requests by allocating a chunk to hold the
126     * single item and immediately placing it into the in-use list.
127     */
128        chainPtr = malloc(sizeof(Rp_PoolChain) + size);
129        if (poolPtr->headPtr == NULL) {
130            poolPtr->headPtr = chainPtr;
131        } else {
132            chainPtr->nextPtr = poolPtr->headPtr->nextPtr;
133            poolPtr->headPtr->nextPtr = chainPtr;
134        }
135        memPtr = (void *)chainPtr;
136    } else {
137        if (poolPtr->bytesLeft >= size) {
138            poolPtr->bytesLeft -= size;
139            memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
140        } else {
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 = malloc(sizeof(Rp_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;
151        }
152    }
153    return memPtr;
154}
155
156/*
157 *----------------------------------------------------------------------
158 *
159 * VariablePoolFreeItem --
160 *
161 *      Placeholder for freeProc routine.  The pool memory is
162 *      not reclaimed or freed until the entire pool is released.
163 *
164 * Results:
165 *      None.
166 *
167 *----------------------------------------------------------------------
168 */
169/*ARGSUSED*/
170static void
171VariablePoolFreeItem(poolPtr, item)
172    struct Rp_PoolStruct *poolPtr;
173    void *item;
174{
175    /* Does nothing */
176}
177
178/*
179 *----------------------------------------------------------------------
180 *
181 * StringPoolAllocItem --
182 *
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.
187 *
188 * Results:
189 *      Returns a new (possible reused) item.
190 *
191 * Side Effects:
192 *      A new memory chunk may be allocated.
193 *
194 *----------------------------------------------------------------------
195 */
196static void *
197StringPoolAllocItem(poolPtr, size)
198    struct Rp_PoolStruct *poolPtr;
199    size_t size;        /* Number of bytes to allocate. */
200{
201    Rp_PoolChain *chainPtr;
202    void *memPtr;
203
204    if (size >= POOL_MAX_CHUNK_SIZE) {
205        /*
206         * Handle oversized requests by allocating a chunk to hold the
207         * single item and immediately placing it into the in-use list.
208         */
209        chainPtr = malloc(sizeof(Rp_PoolChain) + size);
210        if (poolPtr->headPtr == NULL) {
211            poolPtr->headPtr = chainPtr;
212        } else {
213            chainPtr->nextPtr = poolPtr->headPtr->nextPtr;
214            poolPtr->headPtr->nextPtr = chainPtr;
215        }
216        memPtr = (void *)chainPtr;
217    } else {
218        if (poolPtr->bytesLeft >= size) {
219            poolPtr->bytesLeft -= size;
220            memPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
221        } else {
222            poolPtr->waste += poolPtr->bytesLeft;
223            /* Create a new block of items and prepend it to the
224             * in-use list */
225            poolPtr->bytesLeft = POOL_MAX_CHUNK_SIZE;
226            /* Allocate the requested chunk size, plus the header */
227            chainPtr = malloc(sizeof(Rp_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;
233        }
234    }
235    return memPtr;
236}
237
238/*
239 *----------------------------------------------------------------------
240 *
241 * StringPoolFreeItem --
242 *
243 *      Placeholder for freeProc routine.  String pool memory is
244 *      not reclaimed or freed until the entire pool is released.
245 *
246 * Results:
247 *      None.
248 *
249 *----------------------------------------------------------------------
250 */
251/*ARGSUSED*/
252static void
253StringPoolFreeItem(poolPtr, item)
254    struct Rp_PoolStruct *poolPtr;
255    void *item;
256{
257    /* Does nothing */
258}
259
260/*
261 *       The fixed size pool is a chain of malloc'ed blocks.
262 *
263 *             +---------+  +---------+  +---------+
264 *       NULL<-| nextPtr |<-| nextPtr |<-| nextPtr |<- headPtr
265 *             |---------|  |---------|  |---------|
266 *             | chunk1  |  | chunk2  |  | chunk3  |
267 *             +---------+  |         |  |         |
268 *                          +---------+  |         |
269 *                                       |         |
270 *                                       |         |
271 *                                       +---------+
272 *
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).
278 *
279 *      The chain of blocks is only freed when the entire pool is
280 *      destroyed.
281 *
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.
285 *
286 *               chunk1       chunk2       chunk3
287 *            +---------+  +---------+  +---------+
288 *      NULL<-| unused  |  |         |  |         |
289 *            +----^----+  +---------+  +---------+
290 *            | unused  |<-| unused  |<-| unused  |
291 *            +---------+  +---------+  +----^----+
292 *            |         |  |         |  | unused  |
293 *            +---------+  |         |  +----^----+
294 *                         |         |  |    |    |
295 *                         +---------+  +----|----+
296 *                                      | usused  |<- freePtr
297 *                                      +---------+
298 */
299
300/*
301 *----------------------------------------------------------------------
302 *
303 * FixedPoolFreeItem --
304 *
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.
309 *
310 * Results:
311 *      Returns a new (possible reused) item.
312 *
313 * Side Effects:
314 *      A new memory chunk may be allocated.
315 *
316 *----------------------------------------------------------------------
317 */
318static void *
319FixedPoolAllocItem(poolPtr, size)
320    struct Rp_PoolStruct *poolPtr;
321    size_t size;
322{
323    Rp_PoolChain *chainPtr;
324    void *newPtr;
325
326    size = ALIGN(size);
327    if (poolPtr->itemSize == 0) {
328        poolPtr->itemSize = size;
329    }
330    assert(size == poolPtr->itemSize);
331
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. */
341
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. */
347        }
348        /* Allocate the requested chunk size, plus the header */
349        chainPtr = malloc(sizeof(Rp_PoolChain) + poolPtr->bytesLeft);
350        chainPtr->nextPtr = poolPtr->headPtr;
351        poolPtr->headPtr = chainPtr;
352
353        /* Peel off a new item. */
354        poolPtr->bytesLeft -= poolPtr->itemSize;
355        newPtr = (char *)(poolPtr->headPtr + 1) + poolPtr->bytesLeft;
356    }
357    return newPtr;
358}
359
360/*
361 *----------------------------------------------------------------------
362 *
363 * FixedPoolFreeItem --
364 *
365 *      Frees an item.  The actual memory is not freed.  The item
366 *      instead is prepended to a freelist where it may be reclaimed
367 *      and used again.
368 *
369 * Results:
370 *      None.
371 *
372 * Side Effects:
373 *      Item is placed on the pool's free list.
374 *
375 *----------------------------------------------------------------------
376 */
377static void
378FixedPoolFreeItem(poolPtr, item)
379    struct Rp_PoolStruct *poolPtr;
380    void *item;
381{
382    Rp_PoolChain *chainPtr = (Rp_PoolChain *)item;
383
384    /* Prepend the newly deallocated item to the free list. */
385    chainPtr->nextPtr = poolPtr->freePtr;
386    poolPtr->freePtr = chainPtr;
387}
388
389/*
390 *----------------------------------------------------------------------
391 *
392 * Rp_PoolCreate --
393 *
394 *      Creates a new memory pool for fixed-size/variable-size/string
395 *      items.
396 *
397 * Results:
398 *      Returns a pointer to the newly allocated pool.
399 *
400 *----------------------------------------------------------------------
401 */
402
403Rp_Pool
404Rp_PoolCreate(type)
405    int type;
406{
407    struct Rp_PoolStruct *poolPtr;
408
409    poolPtr = malloc(sizeof(struct Rp_PoolStruct));
410    switch (type) {
411    case RP_VARIABLE_SIZE_ITEMS:
412        poolPtr->allocProc = VariablePoolAllocItem;
413        poolPtr->freeProc = VariablePoolFreeItem;
414        break;
415    case RP_FIXED_SIZE_ITEMS:
416        poolPtr->allocProc = FixedPoolAllocItem;
417        poolPtr->freeProc = FixedPoolFreeItem;
418        break;
419    case RP_STRING_ITEMS:
420        poolPtr->allocProc = StringPoolAllocItem;
421        poolPtr->freeProc = StringPoolFreeItem;
422        break;
423    }
424    poolPtr->headPtr = poolPtr->freePtr = NULL;
425    poolPtr->waste = poolPtr->bytesLeft = 0;
426    poolPtr->poolSize = poolPtr->itemSize = 0;
427    return poolPtr;
428}
429
430/*
431 *----------------------------------------------------------------------
432 *
433 * Rp_PoolDestroy --
434 *
435 *      Destroys the given memory pool.  The chain of allocated blocks
436 *      are freed.  The is the only time that memory is actually freed.
437 *
438 * Results:
439 *      None.
440 *
441 * Side Effects:
442 *      All memory used by the pool is freed.
443 *
444 *----------------------------------------------------------------------
445 */
446void
447Rp_PoolDestroy(poolPtr)
448    struct Rp_PoolStruct *poolPtr;
449{
450    register Rp_PoolChain *chainPtr, *nextPtr;
451
452    for (chainPtr = poolPtr->headPtr; chainPtr != NULL; chainPtr = nextPtr) {
453        nextPtr = chainPtr->nextPtr;
454        free(chainPtr);
455    }
456    free(poolPtr);
457}
458
Note: See TracBrowser for help on using the repository browser.