Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

chunkallocator.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  @file  chunkallocator.c
00003  *  @brief chunkallocator Implementation.
00004  *
00005  *  @date   : 15-08-03 00:45
00006  *  @author : Pedro Ortega C. <peortega@dcc.uchile.cl>
00007  *  Copyright  2003  Pedro Ortega C.
00008  ****************************************************************************/
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024 
00025 
00026 
00027 /**
00028  * @brief An efficient memory chunk allocator.
00029  * @defgroup chunkallocator_doc chunkallocator : A Memory Chunk Allocator.
00030  *
00031  * The chunkallocator is a little and simple memory manager for "chunks" or
00032  * bins of constant size. It it designed to be efficient: it allocates and
00033  * frees theese memory bins very fast. On the other side, it isn't as flexible
00034  * the C memory manager (provided by \p malloc() and Co.).
00035  *
00036  * The chunkallocator is a good alternative to \p malloc() for structures such
00037  * as linked list, whose elements are of constant size and are frequently
00038  * allocated and freed.
00039  *
00040  * You can have many different chunkallocators in your application for
00041  * different purposes: they all handle independent memory blocks.
00042  *
00043  * Example usage:
00044    \code
00045 
00046    chunkallocator *c;
00047    List *lst;
00048    
00049    // Allocate a new Memory Chunk Allocator for handling list items.
00050    c = chunkallocator_new (sizeof (List));
00051    
00052    // Allocate memory.
00053    lst = chunkallocator_alloc (c);
00054    
00055    // Free allocated memory.
00056    chunkallocator_free (c, lst);
00057    
00058    // Do more complicated things....
00059    ...
00060    
00061    // After using the memory allocator, free it.
00062    chunkallocator_destroy (c);
00063    
00064    \endcode
00065  */
00066 
00067 
00068 
00069 /******************************************/
00070 /* Include Files                          */
00071 /******************************************/
00072 
00073 #include <stdio.h>
00074 #include <assert.h>
00075 #include <limits.h>
00076 #include <stdlib.h>
00077 #include "chunkallocator.h"
00078 
00079 
00080 
00081 /******************************************/
00082 /* Static Declaration                     */
00083 /******************************************/
00084 
00085 static int
00086 chunkallocator_increase (chunkallocator *a);
00087 
00088 
00089 
00090 /******************************************/
00091 /* Static Implementation                  */
00092 /******************************************/
00093 
00094 /**
00095  * @brief Allocate a new chunkblock.
00096  * @ingroup chunkallocator_doc
00097  *
00098  * This function allocates a new chunkblock that doubles the size of its
00099  * previous block (in the memblock array) and sets the corresponding boundary
00100  * pointer beginptr and endptr.
00101  *
00102  * @param  a A pointer to a chunkallocator.
00103  * @return 0 if O.K., 1 if failed to allocate new chunkblock.
00104  */
00105 static int
00106 chunkallocator_increase (chunkallocator *a)
00107 {
00108     size_t blocksize;
00109 
00110     assert (a->cblock->beginptr == NULL);
00111 
00112     /* compute blocksize */
00113     a->cblock--;
00114     blocksize = 2 * (a->cblock->endptr - a->cblock->beginptr);
00115     a->cblock++;
00116 
00117     /* allocate memory block */
00118     a->cblock->beginptr = (unsigned char *) malloc (blocksize);
00119     if (a->cblock->beginptr == NULL)
00120     {
00121         fprintf (stderr, "chunkallocator: out of memory\n");
00122             return 1;
00123     }
00124 
00125     a->cblock->endptr = a->cblock->beginptr + blocksize;
00126 
00127     return 0;
00128 }
00129 
00130 
00131 
00132 /******************************************/
00133 /* Public Interface Implementation        */
00134 /******************************************/
00135 
00136 /**
00137  * @brief Create a new chunkallocator.
00138  * @ingroup chunkallocator_doc
00139  *
00140  * This function creates a new chunkallocator for bins of the given size.
00141  *
00142  * @param  binsize The size of the bins that the allocator should allocate.
00143  * @return A pointer to a new created chunkallocator.
00144  */
00145 chunkallocator *
00146 chunkallocator_new (size_t binsize)
00147 {
00148     chunkallocator *a;
00149     
00150     /* make sufficient big chunks */
00151     if (binsize < sizeof (unsigned char *))
00152         binsize = sizeof (unsigned char *);
00153     
00154     /* alloc chunkallocator */
00155     a = (chunkallocator *) malloc (sizeof (*a));
00156     if (a == NULL)
00157         return NULL;
00158         
00159     /* set fields */
00160     a->allocated   = 0L;
00161     a->binsize     = binsize;
00162     a->deallocated = 0L;
00163     
00164     /* alloc chunk block array */
00165     a->memblocks =
00166                (chunkblock *) calloc (8 * sizeof (size_t), sizeof (chunkblock));
00167     if (a->memblocks == NULL)
00168     {
00169         free (a);
00170         return NULL;
00171     }
00172     
00173     /* set current memblock pointer */
00174     a->cblock = a->memblocks;
00175     
00176     /* alloc first chunk block */
00177     a->cblock->beginptr =
00178                     (unsigned char *) malloc (CHUNKBLOCK_MINSIZE * a->binsize);
00179     if (a->cblock->beginptr == NULL)
00180     {
00181         free (a->memblocks);
00182         free (a);
00183         return NULL;
00184     }
00185     
00186     /* set block end pointer */
00187     a->cblock->endptr  = a->cblock->beginptr + CHUNKBLOCK_MINSIZE * a->binsize;
00188     
00189     /* set pointer to free chunk */
00190     a->nextfree = a->cblock->beginptr;
00191     
00192     return a;
00193 }
00194 
00195 /**
00196  * @brief Destroy chunkallocator.
00197  * @ingroup chunkallocator_doc
00198  *
00199  * This function frees the memory of the chunkallocator, freeing the structure
00200  * and all its chunk/memory blocks.
00201  *
00202  * @param a A pointer to a chunkallocator.
00203  */
00204 void
00205 chunkallocator_destroy (chunkallocator *a)
00206 {
00207     chunkblock *ptr;
00208     
00209     /* free all memory blocks */
00210     for (ptr = a->memblocks; ptr->beginptr != NULL; ptr++);
00211         free (ptr->beginptr);
00212 
00213     /* free block array */
00214     free (a->memblocks);
00215     free (a);
00216 }
00217 
00218 /**
00219  * @brief Allocate chunk.
00220  * @ingroup chunkallocator_doc
00221  *
00222  * This function returns a pointer to a new allocated memory chunk. The
00223  * chunkallocator handles the memory management to do so, and of course,
00224  * to allocate a chunk of the correct size efficiently.
00225  *
00226  * Internally, the allocator checks if there are dead chunks, that is,
00227  * previously deallocated chunks that lie fragmented in the memory. If so
00228  * it assigns its memory. If not, then it returns new memory from the
00229  * memory pool. If there isn't any memory available either, then it
00230  * creates a new chunkblock.
00231  *
00232  * @param  a A pointer to a chunkallocator.
00233  * @return A pointer to new memory.
00234  */
00235 void *
00236 chunkallocator_alloc (chunkallocator *a)
00237 {
00238     void *memblock;
00239     
00240     assert ((a->nextfree - a->cblock->beginptr) % a->binsize == 0);
00241     assert ((a->cblock->endptr - a->nextfree) % a->binsize == 0);
00242     assert (a->cblock->beginptr <= a->nextfree);
00243     assert (a->nextfree <= a->cblock->endptr);
00244 
00245     /* get if there are recyclable dead chunks */
00246     if (a->deallocated > 0)
00247     {
00248         memblock = a->nextdealloc;
00249         a->nextdealloc = (unsigned char **) *(a->nextdealloc);
00250         a->deallocated--;
00251     }
00252     else
00253     {
00254         /* get free memory block */
00255         memblock = a->nextfree;
00256     
00257         /* point to next free block */
00258         a->nextfree += a->binsize;
00259 
00260         /* jump to next memory block if current is full */
00261         if (a->nextfree == a->cblock->endptr)
00262         {
00263             a->cblock++;
00264         
00265             /* increase memory pool if full */
00266             if (a->cblock->beginptr == NULL)
00267                 if (chunkallocator_increase (a))
00268                 {
00269                     a->cblock--;
00270                     a->nextfree = a->cblock->endptr;
00271                     return NULL;
00272                 }
00273 
00274             a->nextfree = a->cblock->beginptr;
00275         }
00276     }
00277 
00278     /* increase chunk counter */
00279     a->allocated++;
00280 
00281     return memblock;
00282 }
00283 
00284 /**
00285  * @brief Free a chunk.
00286  * @ingroup chunkallocator_doc
00287  *
00288  * This function deallocates the chunk/memory block pointed by the argument.
00289  *
00290  * Internally, the allocator just returns it to the memory pool by linking
00291  * the bin to the list of deallocated (and recyclable) memory chunks.
00292  *
00293  * @param a        A pointer to a chunkallocator.
00294  * @param memblock A pointer to a memory chunk to be freed.
00295  */
00296 void
00297 chunkallocator_free (chunkallocator *a, void *memblock)
00298 {
00299     unsigned char **chunk;
00300     
00301     assert (a->allocated > 0);
00302     assert ((a->nextfree - a->cblock->beginptr) % a->binsize == 0);
00303     assert ((a->cblock->endptr - a->nextfree) % a->binsize == 0);
00304     assert (a->cblock->beginptr <= a->nextfree);
00305     assert (a->nextfree <= a->cblock->endptr);
00306 
00307     /* register dead chunk */
00308     chunk  = memblock;
00309     *chunk = (unsigned char *) a->nextdealloc;
00310     a->nextdealloc = chunk;
00311     a->deallocated++;
00312     a->allocated--;
00313 }
00314 
00315 

Generated on Sun Jun 13 20:50:11 2004 for libgnn Gradient Retropropagation Machine Library by doxygen1.2.18