summaryrefslogtreecommitdiff
path: root/Runtime/Utilities/MemoryPool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Utilities/MemoryPool.cpp')
-rw-r--r--Runtime/Utilities/MemoryPool.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/Runtime/Utilities/MemoryPool.cpp b/Runtime/Utilities/MemoryPool.cpp
new file mode 100644
index 0000000..f11d88a
--- /dev/null
+++ b/Runtime/Utilities/MemoryPool.cpp
@@ -0,0 +1,210 @@
+#include "UnityPrefix.h"
+#include "MemoryPool.h"
+#include "Runtime/Utilities/Word.h"
+#include "Runtime/Profiler/MemoryProfiler.h"
+#include "Runtime/Utilities/InitializeAndCleanup.h"
+
+static int kMinBlockSize = sizeof(void*);
+UNITY_VECTOR(kMemPoolAlloc,MemoryPool*)* MemoryPool::s_MemoryPools = NULL;
+void MemoryPool::StaticInitialize()
+{
+ s_MemoryPools = UNITY_NEW(UNITY_VECTOR(kMemPoolAlloc,MemoryPool*),kMemPoolAlloc);
+}
+
+void MemoryPool::StaticDestroy()
+{
+ for(size_t i = 0; i < s_MemoryPools->size(); i++)
+ UNITY_DELETE((*s_MemoryPools)[i],kMemPoolAlloc);
+ UNITY_DELETE(s_MemoryPools,kMemPoolAlloc);
+}
+
+static RegisterRuntimeInitializeAndCleanup s_MemoryPoolCallbacks(MemoryPool::StaticInitialize, MemoryPool::StaticDestroy);
+
+void MemoryPool::RegisterStaticMemoryPool(MemoryPool* pool)
+{
+ s_MemoryPools->push_back(pool);
+}
+
+MemoryPool::MemoryPool( bool threadCheck, const char* name, int blockSize, int hintSize, MemLabelId label )
+: m_AllocLabel(MemLabelId(label.label, GET_CURRENT_ALLOC_ROOT_HEADER()))
+, m_Bubbles(MemLabelId(label.label, GET_CURRENT_ALLOC_ROOT_HEADER()))
+#if DEBUGMODE
+, m_PeakAllocCount(0)
+, m_Name(name)
+#endif
+{
+ #if ENABLE_THREAD_CHECK_IN_ALLOCS
+ m_ThreadCheck = threadCheck;
+ #endif
+
+ if (blockSize < kMinBlockSize)
+ blockSize = kMinBlockSize;
+ m_BlockSize = blockSize;
+
+
+ m_BubbleSize = hintSize;
+ m_BlocksPerBubble = (m_BubbleSize - sizeof(Bubble) + 1) / blockSize;
+
+ int usedBubbleSize = sizeof(Bubble) + m_BlocksPerBubble * blockSize - 1;
+ Assert(usedBubbleSize <= m_BubbleSize);
+ Assert(m_BubbleSize - usedBubbleSize <= m_BlockSize);
+
+ Assert (m_BlocksPerBubble >= 128);
+ Assert(hintSize % 4096 == 0);
+
+ m_AllocateMemoryAutomatically = true;
+
+ Reset();
+}
+
+MemoryPool::~MemoryPool()
+{
+ #if !UNITY_EDITOR && DEBUGMODE
+ if (m_AllocCount > 0)
+ ErrorStringMsg( "Memory pool has %d unallocated objects: %s", m_AllocCount, m_Name ); // some stuff not deallocated?
+ #endif
+ DeallocateAll();
+}
+
+void MemoryPool::Reset()
+{
+ #if DEBUGMODE
+ m_AllocCount = 0;
+ #endif
+ m_HeadOfFreeList = NULL;
+}
+
+void MemoryPool::DeallocateAll()
+{
+ Bubbles::iterator it, itEnd = m_Bubbles.end();
+ for( it = m_Bubbles.begin(); it != itEnd; ++it )
+ UNITY_FREE( m_AllocLabel, *it );
+ m_Bubbles.clear();
+ Reset();
+}
+
+void MemoryPool::PreallocateMemory (int size)
+{
+ bool temp = m_AllocateMemoryAutomatically;
+ m_AllocateMemoryAutomatically = true;
+ for (int i=0;i <= size / (m_BlocksPerBubble * m_BlockSize);i++)
+ {
+ AllocNewBubble();
+ }
+ m_AllocateMemoryAutomatically = temp;
+}
+
+void MemoryPool::AllocNewBubble( )
+{
+ if (!m_AllocateMemoryAutomatically)
+ return;
+
+ AssertIf (m_BlocksPerBubble == 1); // can't have 1 element per bubble
+
+ Bubble *bubble = (Bubble*)UNITY_MALLOC( m_AllocLabel, m_BubbleSize );
+ AssertIf( !bubble );
+
+ // put to bubble list
+ m_Bubbles.push_back( bubble );
+
+ // setup the free list inside a bubble
+ void* oldHeadOfFreeList = m_HeadOfFreeList;
+ m_HeadOfFreeList = bubble->data;
+ AssertIf( !m_HeadOfFreeList );
+
+ void **newBubble = (void**)m_HeadOfFreeList;
+ for( int j = 0; j < m_BlocksPerBubble-1; ++j )
+ {
+ newBubble[0] = (char*)newBubble + m_BlockSize;
+ newBubble = (void**)newBubble[0];
+ }
+
+ newBubble[0] = oldHeadOfFreeList; // continue with existing free list (or terminate with NULL if no free elements)
+
+ // still failure, error out
+ if( !m_HeadOfFreeList )
+ {
+ ErrorString( "out of memory!" );
+ }
+}
+
+void* MemoryPool::Allocate()
+{
+ return Allocate( m_BlockSize );
+}
+
+void *MemoryPool::Allocate( size_t amount )
+{
+#if ENABLE_THREAD_CHECK_IN_ALLOCS
+ ErrorAndReturnValueIf(m_ThreadCheck && Thread::mainThreadId && !Thread::CurrentThreadIsMainThread(), NULL);
+#endif
+
+
+ void *returnBlock;
+
+ if( amount > (unsigned int)m_BlockSize ) {
+ ErrorString( Format("requested larger amount than block size! requested: %d, blocksize: %d", (unsigned)amount, (unsigned)m_BlockSize ));
+ return NULL;
+ }
+
+ if( !m_HeadOfFreeList ) {
+ // allocate new bubble
+ AllocNewBubble();
+
+ // Can't allocate
+ if( m_HeadOfFreeList == NULL )
+ return NULL;
+ }
+
+ #if DEBUGMODE
+ ++m_AllocCount;
+ if( m_AllocCount > m_PeakAllocCount )
+ m_PeakAllocCount = m_AllocCount;
+ #endif
+
+ returnBlock = m_HeadOfFreeList;
+
+ // move the pointer to the next block
+ m_HeadOfFreeList = *((void**)m_HeadOfFreeList);
+
+ return returnBlock;
+}
+
+void MemoryPool::Deallocate( void *mem_Block )
+{
+#if ENABLE_THREAD_CHECK_IN_ALLOCS
+ ErrorAndReturnIf(m_ThreadCheck && Thread::mainThreadId && !Thread::CurrentThreadIsMainThread());
+#endif
+
+ if( !mem_Block ) // ignore NULL deletes
+ return;
+
+ #if DEBUGMODE
+ // check to see if the memory is from the allocated range
+ bool ok = false;
+ size_t n = m_Bubbles.size();
+ for( size_t i = 0; i < n; ++i ) {
+ Bubble* p = m_Bubbles[i];
+ if( (char*)mem_Block >= p->data && (char*)mem_Block < (p->data + m_BlockSize * m_BlocksPerBubble) ) {
+ ok = true;
+ break;
+ }
+ }
+ AssertIf( !ok );
+ #endif
+
+ #if DEBUGMODE
+ // invalidate the memory
+ memset( mem_Block, 0xDD, m_BlockSize );
+ AssertIf(m_AllocCount == 0);
+ #endif
+
+ #if DEBUGMODE
+ --m_AllocCount;
+ #endif
+
+ // make the block point to the first free item in the list
+ *((void**)mem_Block) = m_HeadOfFreeList;
+ // the list head is now the Deallocated block
+ m_HeadOfFreeList = mem_Block;
+}