Blender V2.61 - r43446

BLI_mempool.c

Go to the documentation of this file.
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 }