Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2008 by Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Geoffery Bantle 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00032 /* 00033 * Simple, fast memory allocator for allocating many elements of the same size. 00034 */ 00035 00036 #include "BLI_utildefines.h" 00037 #include "BLI_listbase.h" 00038 00039 #include "BLI_mempool.h" /* own include */ 00040 00041 #include "DNA_listBase.h" 00042 00043 #include "MEM_guardedalloc.h" 00044 00045 #include <string.h> 00046 #include <stdlib.h> 00047 00048 /* note: copied from BKE_utildefines.h, dont use here because we're in BLI */ 00049 #ifdef __BIG_ENDIAN__ 00050 /* Big Endian */ 00051 # define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) 00052 #else 00053 /* Little Endian */ 00054 # define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) 00055 #endif 00056 00057 #define FREEWORD MAKE_ID('f', 'r', 'e', 'e') 00058 00059 typedef struct BLI_freenode { 00060 struct BLI_freenode *next; 00061 int freeword; /* used to identify this as a freed node */ 00062 } BLI_freenode; 00063 00064 typedef struct BLI_mempool_chunk { 00065 struct BLI_mempool_chunk *next, *prev; 00066 void *data; 00067 } BLI_mempool_chunk; 00068 00069 struct BLI_mempool { 00070 struct ListBase chunks; 00071 int esize; /* element size in bytes */ 00072 int csize; /* chunk size in bytes */ 00073 int pchunk; /* number of elements per chunk */ 00074 short use_sysmalloc, allow_iter; 00075 /* keeps aligned to 16 bits */ 00076 00077 BLI_freenode *free; /* free element list. Interleaved into chunk datas.*/ 00078 int totalloc, totused; /* total number of elements allocated in total, 00079 * and currently in use*/ 00080 }; 00081 00082 #define MEMPOOL_ELEM_SIZE_MIN (sizeof(void *) * 2) 00083 00084 BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk, 00085 short use_sysmalloc, short allow_iter) 00086 { 00087 BLI_mempool *pool = NULL; 00088 BLI_freenode *lasttail = NULL, *curnode = NULL; 00089 int i,j, maxchunks; 00090 char *addr; 00091 00092 if (esize < MEMPOOL_ELEM_SIZE_MIN) 00093 esize = MEMPOOL_ELEM_SIZE_MIN; 00094 00095 /*allocate the pool structure*/ 00096 pool = use_sysmalloc ? malloc(sizeof(BLI_mempool)) : MEM_mallocN(sizeof(BLI_mempool), "memory pool"); 00097 pool->esize = allow_iter ? MAX2(esize, sizeof(BLI_freenode)) : esize; 00098 pool->use_sysmalloc = use_sysmalloc; 00099 pool->pchunk = pchunk; 00100 pool->csize = esize * pchunk; 00101 pool->chunks.first = pool->chunks.last = NULL; 00102 pool->totused= 0; 00103 pool->allow_iter= allow_iter; 00104 00105 maxchunks = tote / pchunk + 1; 00106 if (maxchunks==0) maxchunks = 1; 00107 00108 /*allocate the actual chunks*/ 00109 for (i=0; i < maxchunks; i++) { 00110 BLI_mempool_chunk *mpchunk = use_sysmalloc ? malloc(sizeof(BLI_mempool_chunk)) : MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); 00111 mpchunk->next = mpchunk->prev = NULL; 00112 mpchunk->data = use_sysmalloc ? malloc(pool->csize) : MEM_mallocN(pool->csize, "BLI Mempool Chunk Data"); 00113 BLI_addtail(&(pool->chunks), mpchunk); 00114 00115 if (i==0) { 00116 pool->free = mpchunk->data; /*start of the list*/ 00117 if (pool->allow_iter) 00118 pool->free->freeword = FREEWORD; 00119 } 00120 00121 /*loop through the allocated data, building the pointer structures*/ 00122 for (addr = mpchunk->data, j=0; j < pool->pchunk; j++) { 00123 curnode = ((BLI_freenode*)addr); 00124 addr += pool->esize; 00125 curnode->next = (BLI_freenode*)addr; 00126 if (pool->allow_iter) { 00127 if (j != pool->pchunk-1) 00128 curnode->next->freeword = FREEWORD; 00129 curnode->freeword = FREEWORD; 00130 } 00131 } 00132 /*final pointer in the previously allocated chunk is wrong.*/ 00133 if (lasttail) { 00134 lasttail->next = mpchunk->data; 00135 if (pool->allow_iter) 00136 lasttail->freeword = FREEWORD; 00137 } 00138 00139 /*set the end of this chunks memoryy to the new tail for next iteration*/ 00140 lasttail = curnode; 00141 00142 pool->totalloc += pool->pchunk; 00143 } 00144 /*terminate the list*/ 00145 curnode->next = NULL; 00146 return pool; 00147 } 00148 00149 void *BLI_mempool_alloc(BLI_mempool *pool) 00150 { 00151 void *retval=NULL; 00152 00153 pool->totused++; 00154 00155 if (!(pool->free)) { 00156 BLI_freenode *curnode=NULL; 00157 char *addr; 00158 int j; 00159 00160 /*need to allocate a new chunk*/ 00161 BLI_mempool_chunk *mpchunk = pool->use_sysmalloc ? malloc(sizeof(BLI_mempool_chunk)) : MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk"); 00162 mpchunk->next = mpchunk->prev = NULL; 00163 mpchunk->data = pool->use_sysmalloc ? malloc(pool->csize) : MEM_mallocN(pool->csize, "BLI_Mempool Chunk Data"); 00164 BLI_addtail(&(pool->chunks), mpchunk); 00165 00166 pool->free = mpchunk->data; /*start of the list*/ 00167 if (pool->allow_iter) 00168 pool->free->freeword = FREEWORD; 00169 for(addr = mpchunk->data, j=0; j < pool->pchunk; j++){ 00170 curnode = ((BLI_freenode*)addr); 00171 addr += pool->esize; 00172 curnode->next = (BLI_freenode*)addr; 00173 00174 if (pool->allow_iter) { 00175 curnode->freeword = FREEWORD; 00176 if (j != pool->pchunk-1) 00177 curnode->next->freeword = FREEWORD; 00178 } 00179 } 00180 curnode->next = NULL; /*terminate the list*/ 00181 00182 pool->totalloc += pool->pchunk; 00183 } 00184 00185 retval = pool->free; 00186 if (pool->allow_iter) 00187 pool->free->freeword = 0x7FFFFFFF; 00188 00189 pool->free = pool->free->next; 00190 //memset(retval, 0, pool->esize); 00191 return retval; 00192 } 00193 00194 void *BLI_mempool_calloc(BLI_mempool *pool) 00195 { 00196 void *retval= BLI_mempool_alloc(pool); 00197 memset(retval, 0, pool->esize); 00198 return retval; 00199 } 00200 00201 /* doesnt protect against double frees, dont be stupid! */ 00202 void BLI_mempool_free(BLI_mempool *pool, void *addr) 00203 { 00204 BLI_freenode *newhead = addr; 00205 00206 if (pool->allow_iter) 00207 newhead->freeword = FREEWORD; 00208 newhead->next = pool->free; 00209 pool->free = newhead; 00210 00211 pool->totused--; 00212 00213 /*nothing is in use; free all the chunks except the first*/ 00214 if (pool->totused == 0) { 00215 BLI_freenode *curnode=NULL; 00216 char *tmpaddr=NULL; 00217 int i; 00218 00219 BLI_mempool_chunk *mpchunk=NULL; 00220 BLI_mempool_chunk *first= pool->chunks.first; 00221 00222 BLI_remlink(&pool->chunks, first); 00223 00224 for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk->next) { 00225 if (pool->use_sysmalloc) free(mpchunk->data); 00226 else MEM_freeN(mpchunk->data); 00227 } 00228 00229 pool->use_sysmalloc ? BLI_freelist(&(pool->chunks)) : BLI_freelistN(&(pool->chunks)); 00230 00231 BLI_addtail(&pool->chunks, first); 00232 pool->totalloc = pool->pchunk; 00233 00234 pool->free = first->data; /*start of the list*/ 00235 for (tmpaddr = first->data, i=0; i < pool->pchunk; i++) { 00236 curnode = ((BLI_freenode*)tmpaddr); 00237 tmpaddr += pool->esize; 00238 curnode->next = (BLI_freenode*)tmpaddr; 00239 } 00240 curnode->next = NULL; /*terminate the list*/ 00241 } 00242 } 00243 00244 void *BLI_mempool_findelem(BLI_mempool *pool, int index) 00245 { 00246 if (!pool->allow_iter) { 00247 fprintf(stderr, "%s: Error! you can't iterate over this mempool!\n", __func__); 00248 return NULL; 00249 } 00250 else if ((index >= 0) && (index < pool->totused)) { 00251 /* we could have some faster mem chunk stepping code inline */ 00252 BLI_mempool_iter iter; 00253 void *elem; 00254 BLI_mempool_iternew(pool, &iter); 00255 for (elem= BLI_mempool_iterstep(&iter); index-- != 0; elem= BLI_mempool_iterstep(&iter)) { }; 00256 return elem; 00257 } 00258 00259 return NULL; 00260 } 00261 00262 void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) 00263 { 00264 if (!pool->allow_iter) { 00265 fprintf(stderr, "%s: Error! you can't iterate over this mempool!\n", __func__); 00266 iter->curchunk = NULL; 00267 iter->curindex = 0; 00268 00269 return; 00270 } 00271 00272 iter->pool = pool; 00273 iter->curchunk = pool->chunks.first; 00274 iter->curindex = 0; 00275 } 00276 00277 #if 0 00278 /* unoptimized, more readable */ 00279 00280 static void *bli_mempool_iternext(BLI_mempool_iter *iter) 00281 { 00282 void *ret = NULL; 00283 00284 if (!iter->curchunk || !iter->pool->totused) return NULL; 00285 00286 ret = ((char*)iter->curchunk->data) + iter->pool->esize*iter->curindex; 00287 00288 iter->curindex++; 00289 00290 if (iter->curindex >= iter->pool->pchunk) { 00291 iter->curchunk = iter->curchunk->next; 00292 iter->curindex = 0; 00293 } 00294 00295 return ret; 00296 } 00297 00298 void *BLI_mempool_iterstep(BLI_mempool_iter *iter) 00299 { 00300 BLI_freenode *ret; 00301 00302 do { 00303 ret = bli_mempool_iternext(iter); 00304 } while (ret && ret->freeword == FREEWORD); 00305 00306 return ret; 00307 } 00308 00309 #else 00310 00311 /* optimized version of code above */ 00312 00313 void *BLI_mempool_iterstep(BLI_mempool_iter *iter) 00314 { 00315 BLI_freenode *ret; 00316 00317 if (UNLIKELY(iter->pool->totused == 0)) { 00318 return NULL; 00319 } 00320 00321 do { 00322 if (LIKELY(iter->curchunk)) { 00323 ret = (BLI_freenode *)(((char*)iter->curchunk->data) + iter->pool->esize*iter->curindex); 00324 } 00325 else { 00326 return NULL; 00327 } 00328 00329 if (UNLIKELY(++iter->curindex >= iter->pool->pchunk)) { 00330 iter->curindex = 0; 00331 iter->curchunk = iter->curchunk->next; 00332 } 00333 } while (ret->freeword == FREEWORD); 00334 00335 return ret; 00336 } 00337 00338 #endif 00339 00340 void BLI_mempool_destroy(BLI_mempool *pool) 00341 { 00342 BLI_mempool_chunk *mpchunk=NULL; 00343 00344 if (pool->use_sysmalloc) { 00345 for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk->next) { 00346 free(mpchunk->data); 00347 } 00348 BLI_freelist(&(pool->chunks)); 00349 free(pool); 00350 } 00351 else { 00352 for (mpchunk = pool->chunks.first; mpchunk; mpchunk = mpchunk->next) { 00353 MEM_freeN(mpchunk->data); 00354 } 00355 BLI_freelistN(&(pool->chunks)); 00356 MEM_freeN(pool); 00357 } 00358 }