Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

mempool.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  MEMPOOL.C                                                                           */
00003 /*                                                                                      */
00004 /*  Author: Charles Bloom                                                               */
00005 /*  Description: Fixed size block memory allocator implementation                       */
00006 /*                                                                                      */
00007 /*  The contents of this file are subject to the Genesis3D Public License               */
00008 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00009 /*  compliance with the License. You may obtain a copy of the License at                */
00010 /*  http://www.genesis3d.com                                                            */
00011 /*                                                                                      */
00012 /*  Software distributed under the License is distributed on an "AS IS"                 */
00013 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00014 /*  the License for the specific language governing rights and limitations              */
00015 /*  under the License.                                                                  */
00016 /*                                                                                      */
00017 /*  The Original Code is Genesis3D, released March 25, 1999.                            */
00018 /*Genesis3D Version 1.1 released November 15, 1999                            */
00019 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
00020 /*                                                                                      */
00021 /****************************************************************************************/
00022 #include <string.h>
00023 #include <assert.h>
00024 
00025 #include "mempool.h"
00026 #include "ram.h"
00027 
00028 /*
00029  *      MemPool is a 'root' level object (eg. 'list' uses us).  We sit only above 'Ram'
00030  *              in the heirarchy
00031  *
00032  *  MemPool
00033  *    system for fast Resetting & Freeing of nodes; for use in tree structures
00034  *     requires no traversing for freeing
00035  *    does auto-extending of memory space in case you use more space than
00036  *     expected or if you don't know how much you will need
00037  *      HunkLength is forced to be a multiple of 4
00038  *
00039  */
00040 
00041 #define RamCalloc(size)                 geRam_AllocateClear(size)
00042 #define RamFree(mem)                    geRam_Free(mem)
00043 #define RamRealloc(mem,size)    geRam_Realloc(mem,size)
00044 
00045 #ifndef memclear
00046 #define memclear(mem,size)      memset(mem,0,size);
00047 #endif
00048 
00049 /**********************/
00050 
00051 /*structs:*/
00052 typedef struct MemBlock MemBlock;
00053 struct MemBlock
00054 {
00055         MemBlock * Next;
00056         char * MemBase;
00057         char * MemPtr;
00058         int MemLength;
00059         int MemFree;    // MemPtr + MemFree == MemBase + MemLength
00060 };
00061 
00062 
00063 struct MemPool
00064 {
00065         int HunkLength;
00066         MemBlock * CurMemBlock; // jump into the list
00067         MemBlock * MemList; // list of memblocks
00068         int AutoExtendNumItems;
00069         int NumFreedHunks;
00070         int MaxNumFreedHunks;
00071         void ** FreedHunks;
00072         int NumItemsActive;
00073 };
00074 
00075 int MemBlock_IsValid(MemBlock *mb)
00076 {
00077         if ( ! mb ) return 0;
00078         if ( mb->Next )
00079         {
00080                 if ( ! MemBlock_IsValid(mb->Next) )
00081                         return 0;
00082         }
00083 
00084         assert( geRam_IsValidPtr(mb->MemBase) );
00085 
00086         if ( mb->MemFree < 0 || mb->MemFree > mb->MemLength )
00087                 return 0;
00088         if ( mb->MemPtr != mb->MemBase + (mb->MemLength - mb->MemFree) )
00089                 return 0;
00090 return 1;
00091 }
00092 
00093 int MemPool_IsValid(MemPool * Pool)
00094 {
00095         if ( ! Pool ) return 0;
00096         if ( Pool->NumFreedHunks < 0 || Pool->AutoExtendNumItems < 0
00097                 || Pool->MaxNumFreedHunks < 0 || Pool->NumItemsActive || Pool->HunkLength )
00098                 return 0;
00099         if ( Pool->NumFreedHunks >= Pool->MaxNumFreedHunks ) return 0;
00100 
00101         // make sure curmemblock is in the memblock list
00102         // <> make sure the freedhunks are in the memblocks (this is the most likely error)
00103 
00104         return MemBlock_IsValid(Pool->MemList);
00105 }
00106 
00107 MemPool * MemPool_Create (int HunkLength,int NumHunks,int AutoExtendNumItems)
00108 {
00109 MemPool * Ret;
00110 
00111 if ( (Ret = RamCalloc(sizeof(MemPool))) == NULL )
00112   return(NULL);
00113 
00114 Ret->HunkLength = (HunkLength+3)&(~3);
00115 Ret->CurMemBlock = NULL;
00116 Ret->MemList = NULL;
00117 Ret->NumFreedHunks = 0;
00118 Ret->MaxNumFreedHunks = 16;
00119 Ret->AutoExtendNumItems = AutoExtendNumItems;
00120 Ret->NumItemsActive = 0;
00121 
00122 if ( (Ret->FreedHunks = RamCalloc(Ret->MaxNumFreedHunks*sizeof(void *))) == NULL )
00123 {
00124         RamFree(Ret);
00125         return(NULL);
00126 }
00127 
00128 if ( ! MemPool_Extend(Ret,NumHunks) )
00129 {
00130         RamFree(Ret->FreedHunks);
00131         RamFree(Ret);
00132         return(NULL);
00133 }
00134 
00135 return(Ret);
00136 }
00137 
00138 void MemPool_Destroy(MemPool ** pPool)
00139 {
00140 MemBlock * CurMemBlock;
00141 MemBlock * NextMemBlock;
00142 MemPool * Pool;
00143 
00144         assert(pPool);
00145 
00146         Pool = *pPool;
00147 
00148         if ( Pool == NULL ) return;
00149 
00150         CurMemBlock = Pool->MemList;
00151         while(CurMemBlock)
00152         {
00153                 RamFree(CurMemBlock->MemBase);
00154                 NextMemBlock = CurMemBlock->Next;
00155                 RamFree(CurMemBlock);
00156                 CurMemBlock = NextMemBlock;
00157         }
00158 
00159         RamFree(Pool->FreedHunks);
00160         RamFree(Pool);
00161 
00162         *pPool = NULL;
00163 }
00164 
00165 void * MemPool_GetHunk (MemPool * Pool)
00166 {
00167 void * Ret;
00168 MemBlock * CurMemBlock;
00169 
00170         if ( Pool->NumFreedHunks > 0 )
00171         {
00172                 Pool->NumFreedHunks--;
00173                 Ret = Pool->FreedHunks[Pool->NumFreedHunks];
00174 
00175                 goto GotHunk;
00176         }
00177 
00178         if ( (CurMemBlock = Pool->CurMemBlock) == NULL )
00179                 return(NULL);
00180 
00181         if ( CurMemBlock->MemFree < Pool->HunkLength )
00182         {
00183                 if ( ! MemPool_Extend(Pool,Pool->AutoExtendNumItems) )
00184                                 return(NULL);
00185                 CurMemBlock = Pool->CurMemBlock;
00186         }
00187 
00188         Ret = (void *) CurMemBlock->MemPtr;
00189 
00190         CurMemBlock->MemFree -= Pool->HunkLength;
00191         CurMemBlock->MemPtr     += Pool->HunkLength;
00192 
00193 GotHunk:
00194 
00195 // clear at alloc & reset & Free, not in Get
00196 //      memclear(Ret,Pool->HunkLength);
00197 
00198         Pool->NumItemsActive++;
00199 
00200 return(Ret);
00201 }
00202 
00203 void MemPool_Reset(MemPool * Pool)
00204 {
00205 MemBlock * CurMemBlock;
00206 
00207         Pool->NumFreedHunks = 0;
00208         Pool->NumItemsActive = 0;
00209         Pool->CurMemBlock = Pool->MemList;
00210 
00211         for( CurMemBlock = Pool->MemList; CurMemBlock ; CurMemBlock = CurMemBlock->Next)
00212         {
00213                 CurMemBlock->MemFree = CurMemBlock->MemLength;
00214                 CurMemBlock->MemPtr = CurMemBlock->MemBase;
00215 
00216                 memclear(CurMemBlock->MemBase,CurMemBlock->MemLength);
00217         }
00218 }
00219 
00220 int MemPool_Extend(MemPool * Pool, int NumHunks)
00221 {
00222 MemBlock * NewMemBlock;
00223 
00224         NewMemBlock = Pool->MemList;
00225         while ( NewMemBlock )
00226         {
00227                 if ( NewMemBlock->MemFree > Pool->HunkLength )
00228                 {
00229                         Pool->CurMemBlock = NewMemBlock;
00230                         return(1);
00231                 }
00232                 NewMemBlock = NewMemBlock->Next;
00233         }
00234 
00235         if ( (NewMemBlock = RamCalloc(sizeof(MemBlock))) == NULL )
00236                 return(0);
00237 
00238         NewMemBlock->MemLength = NumHunks * Pool->HunkLength;
00239         NewMemBlock->MemFree = NewMemBlock->MemLength;
00240 
00241         if ( (NewMemBlock->MemBase = RamCalloc(NewMemBlock->MemLength)) == NULL )
00242         {
00243                 RamFree(NewMemBlock);
00244                 return(0);
00245         }
00246 
00247         NewMemBlock->MemPtr = NewMemBlock->MemBase;
00248 
00249         NewMemBlock->Next = Pool->MemList;
00250         Pool->MemList = NewMemBlock;
00251 
00252         Pool->CurMemBlock = NewMemBlock;
00253 
00254 return(1);
00255 }
00256 
00257 int MemPool_FreeHunk(MemPool * Pool,void * Hunk)
00258 {
00259         assert( Pool );
00260         // <> assert Hunk is in Pool !
00261 
00262         // we must use this growing array for Freed Hunks, because
00263         //  to use a linked list of freed hunks, we'd need to use MemPool !!!
00264 
00265         if ( Pool->NumFreedHunks >= Pool->MaxNumFreedHunks )
00266         {
00267                 Pool->MaxNumFreedHunks <<= 1;
00268 
00269                 Pool->FreedHunks = RamRealloc(Pool->FreedHunks,Pool->MaxNumFreedHunks*sizeof(void *));
00270                 assert(Pool->FreedHunks);
00271                 if ( ! Pool->FreedHunks )
00272                         return(0);
00273         }
00274 
00275         Pool->FreedHunks[Pool->NumFreedHunks] = Hunk;
00276         Pool->NumFreedHunks++;
00277 
00278         Pool->NumItemsActive--;
00279 
00280         memclear(Hunk,Pool->HunkLength);
00281 
00282 return(1);
00283 }
00284 
00285 /*************************/
00286 static MemBlock * WalkMemBlock;
00287 static char *WalkPtr,*WalkPtrEnd;
00288 static MemPool * LastPool;
00289 
00290 void * MemPool_WalkNext(MemPool *Pool,void *Hunk)
00291 {
00292         if ( ! Pool ) return NULL;
00293         if ( ! Hunk )
00294         {
00295                 LastPool = Pool;
00296                 WalkMemBlock = Pool->MemList;
00297                 if ( ! WalkMemBlock ) return NULL;
00298                 WalkPtr = WalkMemBlock->MemBase;
00299                 WalkPtrEnd = WalkPtr + (WalkMemBlock->MemLength - WalkMemBlock->MemFree);
00300         }
00301         else
00302         {
00303                 assert( Pool == LastPool );
00304                 assert( WalkPtr == Hunk );
00305                 rewalk:
00306                 WalkPtr += Pool->HunkLength;
00307                 if ( WalkPtr >= WalkPtrEnd )
00308                 {
00309                         WalkMemBlock = WalkMemBlock->Next;
00310                         if ( ! WalkMemBlock ) return NULL;
00311                         WalkPtr = WalkMemBlock->MemBase;
00312                         WalkPtrEnd = WalkPtr + (WalkMemBlock->MemLength - WalkMemBlock->MemFree);
00313                 }
00314         }
00315 
00316         // must check to see if WalkPtr is in the FreedHunks ! 
00317         // this is so slow it makes this function worthless!
00318         {
00319         int i;
00320                 for(i=0;i<Pool->NumFreedHunks;i++)
00321                 {
00322                         if ( WalkPtr == Pool->FreedHunks[i] )
00323                         {
00324                                 Hunk = WalkPtr;
00325                                 goto rewalk;
00326                         }
00327                 }
00328         }
00329 
00330 return WalkPtr;
00331 }

Generated on Tue Sep 30 12:36:00 2003 for GTestAndEngine by doxygen 1.3.2