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

src/MemoryPool.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL 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 SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #include <spl/Exception.h>
00018 #include <spl/io/File.h>
00019 #include <spl/math/Math.h>
00020 #include <spl/collection/MemoryPool.h>
00021 
00022 static const int FREEED_MEMORY_CONTENT        = 0xAA ; 
00023 static const int NEW_ALLOCATED_MEMORY_CONTENT = 0xFF ; 
00024 static const int MP_MAJIC = 27013;
00025 
00026 MemoryPool::MemoryPool(const int blockSize, bool setMemoryData)
00027 : m_totalMemoryPoolSize(0),
00028   m_usedMemoryPoolSize(0),
00029   m_freeMemoryPoolSize(0),
00030   m_memoryBlockSize(blockSize),
00031   m_memoryBlockCount(0),
00032   m_setMemoryData(setMemoryData)
00033 {
00034         m_head.m_data = NULL;
00035         m_head.m_size = 0;
00036         m_head.m_pos = 0;
00037         m_head.m_next = NULL;
00038         m_head.m_checkBits = MP_MAJIC;
00039 }
00040 
00041 MemoryPool::~MemoryPool()
00042 {
00043         ASSERT(m_head.m_checkBits == MP_MAJIC);
00044 
00045         MemoryBlock *mb = m_head.m_next;
00046         while ( NULL != mb )
00047         {
00048                 ASSERT(mb->m_checkBits == MP_MAJIC);
00049                 ASSERT_MEM(mb, sizeof(MemoryBlock));
00050                 ASSERT_MEM(mb->m_data, mb->m_size);
00051                 
00052                 MemoryBlock *next = mb->m_next;
00053                 free(mb->m_data);
00054                 delete mb;
00055                 mb = next;
00056         }
00057         m_head.m_next = NULL;
00058 }
00059 
00060 void *MemoryPool::Malloc(int size)
00061 {
00062         ASSERT(m_head.m_checkBits == MP_MAJIC);
00063 
00064         m_freeMemoryPoolSize -= size;
00065         m_usedMemoryPoolSize += size;
00066 
00067         // add space for the block ID and size
00068         size += 8;
00069 
00070         MemoryBlock *mb;
00071 
00072         if ( size > m_memoryBlockSize )
00073         {
00074                 // For large allocations, just make a special block
00075                 mb = AllocateBlock(size);
00076         }
00077         else
00078         {
00079                 mb = m_head.m_next;
00080                 while ( NULL != mb )
00081                 {
00082                         if ( mb->m_size - mb->m_pos > size )
00083                         {
00084                                 break;
00085                         }
00086                         mb = mb->m_next;
00087                 }
00088                 if ( NULL == mb )
00089                 {
00090                         mb = AllocateBlock(m_memoryBlockSize);
00091                 }
00092         }
00093         void *data = &mb->m_data[mb->m_pos];
00094         *((int32 *)data) = mb->m_blockId;
00095         data = &((byte *)data)[4];
00096         *((int32 *)data) = size;
00097         data = &((byte *)data)[4];
00098 
00099         mb->m_pos += size;
00100         ASSERT( mb->m_pos <= mb->m_size );
00101         return data;
00102 }
00103 
00104 void MemoryPool::Free(void *ptr)
00105 {
00106         ASSERT(m_head.m_checkBits == MP_MAJIC);
00107 
00108         int blockId = *((int32 *)(((byte *)ptr) - 8));
00109         int size = *((int32 *)(((byte *)ptr) - 4));
00110 
00111         MemoryBlock *mb = m_head.m_next;
00112         while ( NULL != mb )
00113         {
00114                 if ( mb->m_blockId == blockId )
00115                 {
00116                         ASSERT( size <= mb->m_size );
00117                         mb->m_freeSize += size;
00118                         ASSERT( mb->m_freeSize <= mb->m_size );
00119                         if ( mb->m_freeSize == mb->m_size )
00120                         {
00121                                 mb->m_freeSize = 0;
00122                                 mb->m_pos = 0;
00123                         }
00124                         return;
00125                 }
00126                 mb = mb->m_next;
00127         }
00128         throw new Exception("MemoryPool::Free: pointer not found");
00129 }
00130 
00131 bool MemoryPool::WriteMemoryDumpToFile(const char *fileName) const
00132 {
00133         spl::IStreamPtr writer = File::OpenWrite(fileName);
00134         
00135         MemoryBlock *mb = m_head.m_next;
00136         while ( NULL != mb )
00137         {
00138                 Array<byte> data(mb->m_data, mb->m_size);
00139                 writer->Write(data);
00140                 mb = mb->m_next;
00141         }
00142         writer->Close();
00143 
00144         return true;
00145 }
00146 
00147 bool MemoryPool::IsValidPointer(const void *ptr) const
00148 {
00149         ASSERT(m_head.m_checkBits == MP_MAJIC);
00150 
00151         int blockId = *((int32 *)(((byte *)ptr) - 8));
00152         int size = *((int32 *)(((byte *)ptr) - 4));
00153 
00154         MemoryBlock *mb = m_head.m_next;
00155         while ( NULL != mb )
00156         {
00157                 if ( mb->m_blockId == blockId )
00158                 {
00159                         ASSERT( size <= mb->m_size );
00160                         return true;;
00161                 }
00162                 mb = mb->m_next;
00163         }
00164         return false;
00165 }
00166 
00167 MemoryBlock *MemoryPool::AllocateBlock(int size)
00168 {
00169         MemoryBlock *mb = (MemoryBlock *)malloc(sizeof(MemoryBlock));
00170         if ( NULL == mb )
00171         {
00172                 throw OutOfMemoryException();
00173         }
00174         memset(mb, 0, sizeof(MemoryBlock));
00175         mb->m_checkBits = MP_MAJIC;
00176         if (NULL == (mb->m_data = (byte *)malloc(size)))
00177         {
00178                 throw OutOfMemoryException();
00179         }
00180 
00181         if ( m_setMemoryData )
00182         {
00183                 memset(mb->m_data, NEW_ALLOCATED_MEMORY_CONTENT, size);
00184         }
00185 
00186         mb->m_blockId = m_memoryBlockCount++;
00187         mb->m_size = size;
00188         mb->m_next = m_head.m_next;
00189         m_head.m_next = mb;
00190 
00191         m_totalMemoryPoolSize += size;
00192         m_freeMemoryPoolSize += size;
00193 
00194         return mb;
00195 }
00196 
00197 #ifdef DEBUG
00198 void MemoryPool::ValidateMem () const
00199 {
00200         ASSERT(m_head.m_checkBits == MP_MAJIC);
00201 
00202         MemoryBlock *mb = m_head.m_next;
00203         while ( NULL != mb )
00204         {
00205                 ASSERT(mb->m_checkBits == MP_MAJIC);
00206                 ASSERT_MEM(mb, sizeof(MemoryBlock));
00207                 ASSERT_MEM(mb->m_data, mb->m_size);
00208                 mb = mb->m_next;
00209         }
00210 }
00211 
00212 void MemoryPool::CheckMem () const
00213 {
00214         ASSERT(m_head.m_checkBits == MP_MAJIC);
00215 
00216         MemoryBlock *mb = m_head.m_next;
00217         while ( NULL != mb )
00218         {
00219                 ASSERT(mb->m_checkBits == MP_MAJIC);
00220                 DEBUG_NOTE_MEM(mb);
00221                 DEBUG_NOTE_MEM(mb->m_data);
00222 
00223                 mb = mb->m_next;
00224         }
00225 }
00226 #endif
00227 
00228 void *operator new (size_t size, MemoryPool& pool)
00229 {
00230         return pool.Malloc((int)size);
00231 }
00232 
00233 void operator delete (void *ptr, MemoryPool& pool)
00234 {
00235         pool.Free(ptr);
00236 }