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
1.2.18