• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

DS_MemoryPool.h

Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 #ifndef __MEMORY_POOL_H
00008 #define __MEMORY_POOL_H
00009 
00010 #ifndef __APPLE__
00011 // Use stdlib and not malloc for compatibility
00012 #include <stdlib.h>
00013 #endif
00014 #include "RakAssert.h"
00015 #include "Export.h"
00016 
00017 #include "RakMemoryOverride.h"
00018 
00019 // DS_MEMORY_POOL_MAX_FREE_PAGES must be > 1
00020 #define DS_MEMORY_POOL_MAX_FREE_PAGES 4
00021 
00022 //#define _DISABLE_MEMORY_POOL
00023 
00024 namespace DataStructures
00025 {
00028         template <class MemoryBlockType>
00029         class RAK_DLL_EXPORT MemoryPool
00030         {
00031         public:
00032                 struct Page;
00033                 struct MemoryWithPage
00034                 {
00035                         MemoryBlockType userMemory;
00036                         Page *parentPage;
00037                 };
00038 
00039                 struct Page
00040                 {
00041                         MemoryWithPage** availableStack;
00042                         int availableStackSize;
00043                         MemoryWithPage* block;
00044                         Page *next, *prev;
00045                 };
00046 
00047                 MemoryPool();
00048                 ~MemoryPool();
00049                 void SetPageSize(int size); // Defaults to 16384 bytes
00050                 MemoryBlockType *Allocate(const char *file, unsigned int line);
00051                 void Release(MemoryBlockType *m, const char *file, unsigned int line);
00052                 void Clear(const char *file, unsigned int line);
00053 
00054                 int GetAvailablePagesSize(void) const {return availablePagesSize;}
00055                 int GetUnavailablePagesSize(void) const {return unavailablePagesSize;}
00056                 int GetMemoryPoolPageSize(void) const {return memoryPoolPageSize;}
00057         protected:
00058                 int BlocksPerPage(void) const;
00059                 void AllocateFirst(void);
00060                 bool InitPage(Page *page, Page *prev, const char *file, unsigned int line);
00061 
00062                 // availablePages contains pages which have room to give the user new blocks.  We return these blocks from the head of the list
00063                 // unavailablePages are pages which are totally full, and from which we do not return new blocks.
00064                 // Pages move from the head of unavailablePages to the tail of availablePages, and from the head of availablePages to the tail of unavailablePages
00065                 Page *availablePages, *unavailablePages;
00066                 int availablePagesSize, unavailablePagesSize;
00067                 int memoryPoolPageSize;
00068         };
00069 
00070         template<class MemoryBlockType>
00071         MemoryPool<MemoryBlockType>::MemoryPool()
00072         {
00073 #ifndef _DISABLE_MEMORY_POOL
00074                 //AllocateFirst();
00075                 availablePagesSize=0;
00076                 unavailablePagesSize=0;
00077                 memoryPoolPageSize=16384;
00078 #endif
00079         }
00080         template<class MemoryBlockType>
00081         MemoryPool<MemoryBlockType>::~MemoryPool()
00082         {
00083 #ifndef _DISABLE_MEMORY_POOL
00084                 Clear(__FILE__, __LINE__);
00085 #endif
00086         }
00087 
00088         template<class MemoryBlockType>
00089         void MemoryPool<MemoryBlockType>::SetPageSize(int size)
00090         {
00091                 memoryPoolPageSize=size;
00092         }
00093 
00094         template<class MemoryBlockType>
00095         MemoryBlockType* MemoryPool<MemoryBlockType>::Allocate(const char *file, unsigned int line)
00096         {
00097 #ifdef _DISABLE_MEMORY_POOL
00098                 return (MemoryBlockType*) rakMalloc_Ex(sizeof(MemoryBlockType), file, line);
00099 #else
00100 
00101                 if (availablePagesSize>0)
00102                 {
00103                         MemoryBlockType *retVal;
00104                         Page *curPage;
00105                         curPage=availablePages;
00106                         retVal = (MemoryBlockType*) curPage->availableStack[--(curPage->availableStackSize)];
00107                         if (curPage->availableStackSize==0)
00108                         {
00109                                 --availablePagesSize;
00110                                 availablePages=curPage->next;
00111                                 RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
00112                                 curPage->next->prev=curPage->prev;
00113                                 curPage->prev->next=curPage->next;
00114 
00115                                 if (unavailablePagesSize++==0)
00116                                 {
00117                                         unavailablePages=curPage;
00118                                         curPage->next=curPage;
00119                                         curPage->prev=curPage;  
00120                                 }
00121                                 else
00122                                 {
00123                                         curPage->next=unavailablePages;
00124                                         curPage->prev=unavailablePages->prev;
00125                                         unavailablePages->prev->next=curPage;
00126                                         unavailablePages->prev=curPage;
00127                                 }                       
00128                         }
00129 
00130                         RakAssert(availablePagesSize==0 || availablePages->availableStackSize>0);
00131                         return retVal;
00132                 }
00133 
00134                 availablePages = (Page *) rakMalloc_Ex(sizeof(Page), file, line);
00135                 if (availablePages==0)
00136                         return 0;
00137                 availablePagesSize=1;
00138                 if (InitPage(availablePages, availablePages, file, line)==false)
00139                         return 0;
00140                 // If this assert hits, we couldn't allocate even 1 block per page. Increase the page size
00141                 RakAssert(availablePages->availableStackSize>1);
00142 
00143                 return (MemoryBlockType *) availablePages->availableStack[--availablePages->availableStackSize];
00144 #endif
00145         }
00146         template<class MemoryBlockType>
00147         void MemoryPool<MemoryBlockType>::Release(MemoryBlockType *m, const char *file, unsigned int line)
00148         {
00149 #ifdef _DISABLE_MEMORY_POOL
00150                 rakFree_Ex(m, file, line);
00151                 return;
00152 #else
00153                 // Find the page this block is in and return it.
00154                 Page *curPage;
00155                 MemoryWithPage *memoryWithPage = (MemoryWithPage*)m;
00156                 curPage=memoryWithPage->parentPage;
00157 
00158                 if (curPage->availableStackSize==0)
00159                 {
00160                         // The page is in the unavailable list so move it to the available list
00161                         curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
00162                         unavailablePagesSize--;
00163 
00164                         // As this page is no longer totally empty, move it to the end of available pages
00165                         curPage->next->prev=curPage->prev;
00166                         curPage->prev->next=curPage->next;
00167                         
00168                         if (unavailablePagesSize>0 && curPage==unavailablePages)
00169                                 unavailablePages=unavailablePages->next;
00170                         
00171                         if (availablePagesSize++==0)
00172                         {
00173                                 availablePages=curPage;
00174                                 curPage->next=curPage;
00175                                 curPage->prev=curPage;
00176                         }
00177                         else
00178                         {
00179                                 curPage->next=availablePages;
00180                                 curPage->prev=availablePages->prev;
00181                                 availablePages->prev->next=curPage;
00182                                 availablePages->prev=curPage;   
00183                         }
00184                 }
00185                 else
00186                 {
00187                         curPage->availableStack[curPage->availableStackSize++]=memoryWithPage;
00188 
00189                         if (curPage->availableStackSize==BlocksPerPage() &&
00190                                 availablePagesSize>=DS_MEMORY_POOL_MAX_FREE_PAGES)
00191                         {
00192                                 // After a certain point, just deallocate empty pages rather than keep them around
00193                                 if (curPage==availablePages)
00194                                 {
00195                                         availablePages=curPage->next;
00196                                         RakAssert(availablePages->availableStackSize>0);
00197                                 }
00198                                 curPage->prev->next=curPage->next;
00199                                 curPage->next->prev=curPage->prev;
00200                                 availablePagesSize--;
00201                                 rakFree_Ex(curPage->availableStack, file, line );
00202                                 rakFree_Ex(curPage->block, file, line );
00203                                 rakFree_Ex(curPage, file, line );
00204                         }
00205                 }
00206 #endif
00207         }
00208         template<class MemoryBlockType>
00209         void MemoryPool<MemoryBlockType>::Clear(const char *file, unsigned int line)
00210         {
00211 #ifdef _DISABLE_MEMORY_POOL
00212                 return;
00213 #else
00214                 Page *cur, *freed;
00215 
00216                 if (availablePagesSize>0)
00217                 {
00218                         cur = availablePages;
00219 #ifdef _MSC_VER
00220 #pragma warning(disable:4127)   // conditional expression is constant
00221 #endif
00222                         while (true) 
00223                         // do
00224                         {
00225                                 rakFree_Ex(cur->availableStack, file, line );
00226                                 rakFree_Ex(cur->block, file, line );
00227                                 freed=cur;
00228                                 cur=cur->next;
00229                                 if (cur==availablePages)
00230                                 {
00231                                         rakFree_Ex(freed, file, line );
00232                                         break;
00233                                 }
00234                                 rakFree_Ex(freed, file, line );
00235                         }// while(cur!=availablePages);
00236                 }
00237                 
00238                 if (unavailablePagesSize>0)
00239                 {
00240                         cur = unavailablePages;
00241                         while (1)
00242                         //do 
00243                         {
00244                                 rakFree_Ex(cur->availableStack, file, line );
00245                                 rakFree_Ex(cur->block, file, line );
00246                                 freed=cur;
00247                                 cur=cur->next;
00248                                 if (cur==unavailablePages)
00249                                 {
00250                                         rakFree_Ex(freed, file, line );
00251                                         break;
00252                                 }
00253                                 rakFree_Ex(freed, file, line );
00254                         } // while(cur!=unavailablePages);
00255                 }
00256 
00257                 availablePagesSize=0;
00258                 unavailablePagesSize=0;
00259 #endif
00260         }
00261         template<class MemoryBlockType>
00262         int MemoryPool<MemoryBlockType>::BlocksPerPage(void) const
00263         {
00264                 return memoryPoolPageSize / sizeof(MemoryWithPage);
00265         }
00266         template<class MemoryBlockType>
00267         bool MemoryPool<MemoryBlockType>::InitPage(Page *page, Page *prev, const char *file, unsigned int line)
00268         {
00269                 int i=0;
00270                 const int bpp = BlocksPerPage();
00271                 page->block=(MemoryWithPage*) rakMalloc_Ex(memoryPoolPageSize, file, line);
00272                 if (page->block==0)
00273                         return false;
00274                 page->availableStack=(MemoryWithPage**)rakMalloc_Ex(sizeof(MemoryWithPage*)*bpp, file, line);
00275                 if (page->availableStack==0)
00276                 {
00277                         rakFree_Ex(page->block, file, line );
00278                         return false;
00279                 }
00280                 MemoryWithPage *curBlock = page->block;
00281                 MemoryWithPage **curStack = page->availableStack;
00282                 while (i < bpp)
00283                 {
00284                         curBlock->parentPage=page;
00285                         curStack[i]=curBlock++;
00286                         i++;
00287                 }
00288                 page->availableStackSize=bpp;
00289                 page->next=availablePages;
00290                 page->prev=prev;
00291                 return true;
00292         }
00293 }
00294 
00295 #endif

Generated on Thu Sep 30 2010 01:27:22 for RakNet by  doxygen 1.7.1