|
@@ -138,166 +138,86 @@ void* allocAligned(
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-/// The hidden implementation of HeapMemoryPool
|
|
|
|
|
-class HeapMemoryPool::Implementation: public NonCopyable
|
|
|
|
|
|
|
+HeapMemoryPool::HeapMemoryPool()
|
|
|
|
|
+{}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+HeapMemoryPool::~HeapMemoryPool()
|
|
|
{
|
|
{
|
|
|
-public:
|
|
|
|
|
- AtomicU32 m_refcount;
|
|
|
|
|
- AtomicU32 m_allocationsCount;
|
|
|
|
|
- AllocAlignedCallback m_allocCb;
|
|
|
|
|
- void* m_allocCbUserData;
|
|
|
|
|
-#if ANKI_MEM_SIGNATURES
|
|
|
|
|
- Signature m_signature;
|
|
|
|
|
- static const U32 MAX_ALIGNMENT = 16;
|
|
|
|
|
- U32 m_headerSize;
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_refcount == 0 && "Refcount should be zero");
|
|
|
|
|
|
|
|
- ~Implementation()
|
|
|
|
|
|
|
+ if(m_allocationsCount != 0)
|
|
|
{
|
|
{
|
|
|
- if(m_allocationsCount != 0)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGW("Memory pool destroyed before all memory being released");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ANKI_LOGW("Memory pool destroyed before all memory being released");
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- void create(AllocAlignedCallback allocCb, void* allocCbUserData)
|
|
|
|
|
- {
|
|
|
|
|
- m_refcount = 1;
|
|
|
|
|
- m_allocationsCount = 0;
|
|
|
|
|
- m_allocCb = allocCb;
|
|
|
|
|
- m_allocCbUserData = allocCbUserData;
|
|
|
|
|
-#if ANKI_MEM_SIGNATURES
|
|
|
|
|
- m_signature = computeSignature(this);
|
|
|
|
|
- m_headerSize = getAlignedRoundUp(MAX_ALIGNMENT, sizeof(Signature));
|
|
|
|
|
-#endif
|
|
|
|
|
- }
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Error HeapMemoryPool::create(
|
|
|
|
|
+ AllocAlignedCallback allocCb, void* allocCbUserData)
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(m_allocCb == nullptr);
|
|
|
|
|
+ ANKI_ASSERT(allocCb != nullptr);
|
|
|
|
|
|
|
|
- void* allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
- {
|
|
|
|
|
|
|
+ m_refcount = 0;
|
|
|
|
|
+ m_allocationsCount = 0;
|
|
|
|
|
+ m_allocCb = allocCb;
|
|
|
|
|
+ m_allocCbUserData = allocCbUserData;
|
|
|
#if ANKI_MEM_SIGNATURES
|
|
#if ANKI_MEM_SIGNATURES
|
|
|
- ANKI_ASSERT(alignment <= MAX_ALIGNMENT && "Wrong assumption");
|
|
|
|
|
- size += m_headerSize;
|
|
|
|
|
|
|
+ m_signature = computeSignature(this);
|
|
|
|
|
+ m_headerSize = getAlignedRoundUp(MAX_ALIGNMENT, sizeof(Signature));
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
- void* mem = m_allocCb(m_allocCbUserData, nullptr, size, alignment);
|
|
|
|
|
-
|
|
|
|
|
- if(mem != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- ++m_allocationsCount;
|
|
|
|
|
|
|
+ return ErrorCode::NONE;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void* HeapMemoryPool::allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
+{
|
|
|
#if ANKI_MEM_SIGNATURES
|
|
#if ANKI_MEM_SIGNATURES
|
|
|
- memset(mem, 0, m_headerSize);
|
|
|
|
|
- memcpy(mem, &m_signature, sizeof(m_signature));
|
|
|
|
|
- U8* memU8 = static_cast<U8*>(mem);
|
|
|
|
|
- memU8 += m_headerSize;
|
|
|
|
|
- mem = static_cast<void*>(memU8);
|
|
|
|
|
|
|
+ ANKI_ASSERT(alignment <= MAX_ALIGNMENT && "Wrong assumption");
|
|
|
|
|
+ size += m_headerSize;
|
|
|
#endif
|
|
#endif
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGE("Out of memory");
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- return mem;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ void* mem = m_allocCb(m_allocCbUserData, nullptr, size, alignment);
|
|
|
|
|
|
|
|
- Bool free(void* ptr)
|
|
|
|
|
|
|
+ if(mem != nullptr)
|
|
|
{
|
|
{
|
|
|
-#if ANKI_MEM_SIGNATURES
|
|
|
|
|
- U8* memU8 = static_cast<U8*>(ptr);
|
|
|
|
|
- memU8 -= m_headerSize;
|
|
|
|
|
- if(memcmp(memU8, &m_signature, sizeof(m_signature)) != 0)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGE("Signature missmatch on free");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ++m_allocationsCount;
|
|
|
|
|
|
|
|
- ptr = static_cast<void*>(memU8);
|
|
|
|
|
|
|
+#if ANKI_MEM_SIGNATURES
|
|
|
|
|
+ memset(mem, 0, m_headerSize);
|
|
|
|
|
+ memcpy(mem, &m_signature, sizeof(m_signature));
|
|
|
|
|
+ U8* memU8 = static_cast<U8*>(mem);
|
|
|
|
|
+ memU8 += m_headerSize;
|
|
|
|
|
+ mem = static_cast<void*>(memU8);
|
|
|
#endif
|
|
#endif
|
|
|
- --m_allocationsCount;
|
|
|
|
|
- m_allocCb(m_allocCbUserData, ptr, 0, 0);
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-HeapMemoryPool& HeapMemoryPool::operator=(const HeapMemoryPool& other)
|
|
|
|
|
-{
|
|
|
|
|
- clear();
|
|
|
|
|
-
|
|
|
|
|
- if(other.m_impl)
|
|
|
|
|
- {
|
|
|
|
|
- m_impl = other.m_impl;
|
|
|
|
|
- ++m_impl->m_refcount;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return *this;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-Error HeapMemoryPool::create(
|
|
|
|
|
- AllocAlignedCallback allocCb, void* allocCbUserData)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(allocCb != nullptr);
|
|
|
|
|
-
|
|
|
|
|
- Error error = ErrorCode::NONE;
|
|
|
|
|
- m_impl = static_cast<Implementation*>(allocCb(allocCbUserData, nullptr,
|
|
|
|
|
- sizeof(Implementation), alignof(Implementation)));
|
|
|
|
|
-
|
|
|
|
|
- if(m_impl)
|
|
|
|
|
- {
|
|
|
|
|
- m_impl->create(allocCb, allocCbUserData);
|
|
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
ANKI_LOGE("Out of memory");
|
|
ANKI_LOGE("Out of memory");
|
|
|
- error = ErrorCode::OUT_OF_MEMORY;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return error;
|
|
|
|
|
|
|
+ return mem;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void HeapMemoryPool::clear()
|
|
|
|
|
|
|
+Bool HeapMemoryPool::free(void* ptr)
|
|
|
{
|
|
{
|
|
|
- if(m_impl)
|
|
|
|
|
|
|
+#if ANKI_MEM_SIGNATURES
|
|
|
|
|
+ U8* memU8 = static_cast<U8*>(ptr);
|
|
|
|
|
+ memU8 -= m_headerSize;
|
|
|
|
|
+ if(memcmp(memU8, &m_signature, sizeof(m_signature)) != 0)
|
|
|
{
|
|
{
|
|
|
- U32 refcount = --m_impl->m_refcount;
|
|
|
|
|
-
|
|
|
|
|
- if(refcount == 0)
|
|
|
|
|
- {
|
|
|
|
|
- auto allocCb = m_impl->m_allocCb;
|
|
|
|
|
- auto ud = m_impl->m_allocCbUserData;
|
|
|
|
|
- ANKI_ASSERT(allocCb);
|
|
|
|
|
-
|
|
|
|
|
- m_impl->~Implementation();
|
|
|
|
|
- allocCb(ud, m_impl, 0, 0);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- m_impl = nullptr;
|
|
|
|
|
|
|
+ ANKI_LOGE("Signature missmatch on free");
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void* HeapMemoryPool::allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->allocate(size, alignment);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-Bool HeapMemoryPool::free(void* ptr)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->free(ptr);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-U32 HeapMemoryPool::getAllocationsCount() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
|
|
+ ptr = static_cast<void*>(memU8);
|
|
|
|
|
+#endif
|
|
|
|
|
+ --m_allocationsCount;
|
|
|
|
|
+ m_allocCb(m_allocCbUserData, ptr, 0, 0);
|
|
|
|
|
|
|
|
- return m_impl->m_allocationsCount.load();
|
|
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
@@ -305,352 +225,188 @@ U32 HeapMemoryPool::getAllocationsCount() const
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-/// The hidden implementation of StackMemoryPool
|
|
|
|
|
-class StackMemoryPool::Implementation: public NonCopyable
|
|
|
|
|
-{
|
|
|
|
|
-public:
|
|
|
|
|
- /// The header of each allocation
|
|
|
|
|
- class MemoryBlockHeader
|
|
|
|
|
- {
|
|
|
|
|
- public:
|
|
|
|
|
- U8 m_size[sizeof(U32)]; ///< It's U8 to allow whatever alignment
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- static_assert(alignof(MemoryBlockHeader) == 1, "Alignment error");
|
|
|
|
|
- static_assert(sizeof(MemoryBlockHeader) == sizeof(U32), "Size error");
|
|
|
|
|
-
|
|
|
|
|
- /// Refcount
|
|
|
|
|
- AtomicU32 m_refcount;
|
|
|
|
|
|
|
+StackMemoryPool::StackMemoryPool()
|
|
|
|
|
+{}
|
|
|
|
|
|
|
|
- /// User allocation function
|
|
|
|
|
- AllocAlignedCallback m_allocCb;
|
|
|
|
|
-
|
|
|
|
|
- /// User allocation function data
|
|
|
|
|
- void* m_allocCbUserData;
|
|
|
|
|
-
|
|
|
|
|
- /// Alignment of allocations
|
|
|
|
|
- PtrSize m_alignmentBytes;
|
|
|
|
|
-
|
|
|
|
|
- /// Aligned size of MemoryBlockHeader
|
|
|
|
|
- PtrSize m_headerSize;
|
|
|
|
|
-
|
|
|
|
|
- /// Pre-allocated memory chunk
|
|
|
|
|
- U8* m_memory;
|
|
|
|
|
-
|
|
|
|
|
- /// Size of the pre-allocated memory chunk
|
|
|
|
|
- PtrSize m_memsize;
|
|
|
|
|
-
|
|
|
|
|
- /// Points to the memory and more specifically to the top of the stack
|
|
|
|
|
- Atomic<U8*> m_top;
|
|
|
|
|
-
|
|
|
|
|
- AtomicU32 m_allocationsCount;
|
|
|
|
|
-
|
|
|
|
|
- // Destroy
|
|
|
|
|
- ~Implementation()
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+StackMemoryPool::~StackMemoryPool()
|
|
|
|
|
+{
|
|
|
|
|
+ if(m_memory != nullptr)
|
|
|
{
|
|
{
|
|
|
- if(m_memory != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
#if ANKI_DEBUG
|
|
#if ANKI_DEBUG
|
|
|
- // Invalidate the memory
|
|
|
|
|
- memset(m_memory, 0xCC, m_memsize);
|
|
|
|
|
|
|
+ // Invalidate the memory
|
|
|
|
|
+ memset(m_memory, 0xCC, m_memsize);
|
|
|
#endif
|
|
#endif
|
|
|
- m_allocCb(m_allocCbUserData, m_memory, 0, 0);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ m_allocCb(m_allocCbUserData, m_memory, 0, 0);
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Construct
|
|
|
|
|
- Error create(AllocAlignedCallback allocCb, void* allocCbUserData,
|
|
|
|
|
- PtrSize size, PtrSize alignmentBytes)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(allocCb);
|
|
|
|
|
- ANKI_ASSERT(size > 0);
|
|
|
|
|
- ANKI_ASSERT(alignmentBytes > 0);
|
|
|
|
|
-
|
|
|
|
|
- Error error = ErrorCode::NONE;
|
|
|
|
|
-
|
|
|
|
|
- m_refcount = 1;
|
|
|
|
|
- m_allocCb = allocCb;
|
|
|
|
|
- m_allocCbUserData = allocCbUserData;
|
|
|
|
|
- m_alignmentBytes = alignmentBytes;
|
|
|
|
|
- m_memsize = getAlignedRoundUp(alignmentBytes, size);
|
|
|
|
|
- m_allocationsCount = 0;
|
|
|
|
|
-
|
|
|
|
|
- m_memory = (U8*)m_allocCb(
|
|
|
|
|
- m_allocCbUserData, nullptr, m_memsize, m_alignmentBytes);
|
|
|
|
|
-
|
|
|
|
|
- if(m_memory != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
-#if ANKI_DEBUG
|
|
|
|
|
- // Invalidate the memory
|
|
|
|
|
- memset(m_memory, 0xCC, m_memsize);
|
|
|
|
|
-#endif
|
|
|
|
|
-
|
|
|
|
|
- // Align allocated memory
|
|
|
|
|
- m_top = m_memory;
|
|
|
|
|
-
|
|
|
|
|
- // Calc header size
|
|
|
|
|
- m_headerSize =
|
|
|
|
|
- getAlignedRoundUp(m_alignmentBytes, sizeof(MemoryBlockHeader));
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGE("Out of memory");
|
|
|
|
|
- error = ErrorCode::OUT_OF_MEMORY;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return error;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Error StackMemoryPool::create(
|
|
|
|
|
+ AllocAlignedCallback allocCb, void* allocCbUserData,
|
|
|
|
|
+ PtrSize size, PtrSize alignmentBytes)
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(allocCb);
|
|
|
|
|
+ ANKI_ASSERT(size > 0);
|
|
|
|
|
+ ANKI_ASSERT(alignmentBytes > 0);
|
|
|
|
|
|
|
|
- PtrSize getTotalSize() const
|
|
|
|
|
- {
|
|
|
|
|
- return m_memsize;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Error error = ErrorCode::NONE;
|
|
|
|
|
|
|
|
- PtrSize getAllocatedSize() const
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
- return m_top.load() - m_memory;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ m_refcount = 0;
|
|
|
|
|
+ m_allocCb = allocCb;
|
|
|
|
|
+ m_allocCbUserData = allocCbUserData;
|
|
|
|
|
+ m_alignmentBytes = alignmentBytes;
|
|
|
|
|
+ m_memsize = getAlignedRoundUp(alignmentBytes, size);
|
|
|
|
|
+ m_allocationsCount = 0;
|
|
|
|
|
|
|
|
- const void* getBaseAddress() const
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
- return m_memory;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ m_memory = reinterpret_cast<U8*>(m_allocCb(
|
|
|
|
|
+ m_allocCbUserData, nullptr, m_memsize, m_alignmentBytes));
|
|
|
|
|
|
|
|
- /// Allocate
|
|
|
|
|
- void* allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
|
|
+ if(m_memory != nullptr)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
- ANKI_ASSERT(alignment <= m_alignmentBytes);
|
|
|
|
|
- (void)alignment;
|
|
|
|
|
-
|
|
|
|
|
- size = getAlignedRoundUp(m_alignmentBytes, size + m_headerSize);
|
|
|
|
|
-
|
|
|
|
|
- ANKI_ASSERT(size < MAX_U32 && "Too big allocation");
|
|
|
|
|
-
|
|
|
|
|
- U8* out = m_top.fetch_add(size);
|
|
|
|
|
-
|
|
|
|
|
- if(out + size <= m_memory + m_memsize)
|
|
|
|
|
- {
|
|
|
|
|
#if ANKI_DEBUG
|
|
#if ANKI_DEBUG
|
|
|
- // Invalidate the block
|
|
|
|
|
- memset(out, 0xCC, size);
|
|
|
|
|
|
|
+ // Invalidate the memory
|
|
|
|
|
+ memset(m_memory, 0xCC, m_memsize);
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
- // Write the block header
|
|
|
|
|
- MemoryBlockHeader* header =
|
|
|
|
|
- reinterpret_cast<MemoryBlockHeader*>(out);
|
|
|
|
|
- U32 size32 = size;
|
|
|
|
|
- memcpy(&header->m_size[0], &size32, sizeof(U32));
|
|
|
|
|
-
|
|
|
|
|
- // Set the correct output
|
|
|
|
|
- out += m_headerSize;
|
|
|
|
|
-
|
|
|
|
|
- // Check alignment
|
|
|
|
|
- ANKI_ASSERT(isAligned(m_alignmentBytes, out));
|
|
|
|
|
-
|
|
|
|
|
- // Increase count
|
|
|
|
|
- ++m_allocationsCount;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // Not always an error
|
|
|
|
|
- out = nullptr;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Align allocated memory
|
|
|
|
|
+ m_top = m_memory;
|
|
|
|
|
|
|
|
- return out;
|
|
|
|
|
|
|
+ // Calc header size
|
|
|
|
|
+ m_headerSize =
|
|
|
|
|
+ getAlignedRoundUp(m_alignmentBytes, sizeof(MemoryBlockHeader));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /// Free
|
|
|
|
|
- Bool free(void* ptr)
|
|
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
- // ptr shouldn't be null or not aligned. If not aligned it was not
|
|
|
|
|
- // allocated by this class
|
|
|
|
|
- ANKI_ASSERT(ptr != nullptr && isAligned(m_alignmentBytes, ptr));
|
|
|
|
|
-
|
|
|
|
|
- // memory is nullptr if moved
|
|
|
|
|
- ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
-
|
|
|
|
|
- // Correct the p
|
|
|
|
|
- U8* realptr = (U8*)ptr - m_headerSize;
|
|
|
|
|
-
|
|
|
|
|
- // realptr should be inside the pool's preallocated memory
|
|
|
|
|
- ANKI_ASSERT(realptr >= m_memory);
|
|
|
|
|
-
|
|
|
|
|
- // Get block size
|
|
|
|
|
- MemoryBlockHeader* header = (MemoryBlockHeader*)realptr;
|
|
|
|
|
- U32 size;
|
|
|
|
|
- memcpy(&size, &header->m_size[0], sizeof(U32));
|
|
|
|
|
|
|
+ ANKI_LOGE("Out of memory");
|
|
|
|
|
+ error = ErrorCode::OUT_OF_MEMORY;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Check if the size is within limits
|
|
|
|
|
- ANKI_ASSERT(realptr + size <= m_memory + m_memsize);
|
|
|
|
|
|
|
+ return error;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Atomic stuff
|
|
|
|
|
- U8* expected = realptr + size;
|
|
|
|
|
- U8* desired = realptr;
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void* StackMemoryPool::allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
+ ANKI_ASSERT(alignment <= m_alignmentBytes);
|
|
|
|
|
+ (void)alignment;
|
|
|
|
|
|
|
|
- // if(top == expected) {
|
|
|
|
|
- // top = desired;
|
|
|
|
|
- // exchange = true;
|
|
|
|
|
- // } else {
|
|
|
|
|
- // expected = top;
|
|
|
|
|
- // exchange = false;
|
|
|
|
|
- // }
|
|
|
|
|
- Bool exchange = m_top.compare_exchange_strong(expected, desired);
|
|
|
|
|
|
|
+ size = getAlignedRoundUp(m_alignmentBytes, size + m_headerSize);
|
|
|
|
|
|
|
|
- // Decrease count
|
|
|
|
|
- --m_allocationsCount;
|
|
|
|
|
|
|
+ ANKI_ASSERT(size < MAX_U32 && "Too big allocation");
|
|
|
|
|
|
|
|
- return exchange;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ U8* out = m_top.fetch_add(size);
|
|
|
|
|
|
|
|
- /// Reset
|
|
|
|
|
- void reset()
|
|
|
|
|
|
|
+ if(out + size <= m_memory + m_memsize)
|
|
|
{
|
|
{
|
|
|
- // memory is nullptr if moved
|
|
|
|
|
- ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
-
|
|
|
|
|
#if ANKI_DEBUG
|
|
#if ANKI_DEBUG
|
|
|
- // Invalidate the memory
|
|
|
|
|
- memset(m_memory, 0xCC, m_memsize);
|
|
|
|
|
|
|
+ // Invalidate the block
|
|
|
|
|
+ memset(out, 0xCC, size);
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
- m_top = m_memory;
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ // Write the block header
|
|
|
|
|
+ MemoryBlockHeader* header =
|
|
|
|
|
+ reinterpret_cast<MemoryBlockHeader*>(out);
|
|
|
|
|
+ U32 size32 = size;
|
|
|
|
|
+ memcpy(&header->m_size[0], &size32, sizeof(U32));
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-StackMemoryPool& StackMemoryPool::operator=(const StackMemoryPool& other)
|
|
|
|
|
-{
|
|
|
|
|
- clear();
|
|
|
|
|
|
|
+ // Set the correct output
|
|
|
|
|
+ out += m_headerSize;
|
|
|
|
|
|
|
|
- if(other.m_impl)
|
|
|
|
|
- {
|
|
|
|
|
- m_impl = other.m_impl;
|
|
|
|
|
- ++m_impl->m_refcount;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return *this;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-Error StackMemoryPool::create(
|
|
|
|
|
- AllocAlignedCallback alloc, void* allocUserData,
|
|
|
|
|
- PtrSize size, PtrSize alignmentBytes)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl == nullptr);
|
|
|
|
|
|
|
+ // Check alignment
|
|
|
|
|
+ ANKI_ASSERT(isAligned(m_alignmentBytes, out));
|
|
|
|
|
|
|
|
- Error error = ErrorCode::NONE;
|
|
|
|
|
- m_impl = static_cast<Implementation*>(alloc(allocUserData, nullptr,
|
|
|
|
|
- sizeof(Implementation), alignof(Implementation)));
|
|
|
|
|
-
|
|
|
|
|
- if(m_impl)
|
|
|
|
|
- {
|
|
|
|
|
- construct(m_impl);
|
|
|
|
|
- error = m_impl->create(alloc, allocUserData, size, alignmentBytes);
|
|
|
|
|
|
|
+ // Increase count
|
|
|
|
|
+ ++m_allocationsCount;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- ANKI_LOGE("Out of memory");
|
|
|
|
|
- error = ErrorCode::OUT_OF_MEMORY;
|
|
|
|
|
|
|
+ // Not always an error
|
|
|
|
|
+ if(!m_ignoreAllocationErrors)
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_LOGE("Out of memory");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ out = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return error;
|
|
|
|
|
|
|
+ return out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void StackMemoryPool::clear()
|
|
|
|
|
|
|
+Bool StackMemoryPool::free(void* ptr)
|
|
|
{
|
|
{
|
|
|
- if(m_impl)
|
|
|
|
|
- {
|
|
|
|
|
- U32 refcount = --m_impl->m_refcount;
|
|
|
|
|
|
|
+ // ptr shouldn't be null or not aligned. If not aligned it was not
|
|
|
|
|
+ // allocated by this class
|
|
|
|
|
+ ANKI_ASSERT(ptr != nullptr && isAligned(m_alignmentBytes, ptr));
|
|
|
|
|
|
|
|
- if(refcount == 0)
|
|
|
|
|
- {
|
|
|
|
|
- auto allocCb = m_impl->m_allocCb;
|
|
|
|
|
- auto ud = m_impl->m_allocCbUserData;
|
|
|
|
|
- ANKI_ASSERT(allocCb);
|
|
|
|
|
|
|
+ // memory is nullptr if moved
|
|
|
|
|
+ ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
|
|
|
- m_impl->~Implementation();
|
|
|
|
|
- allocCb(ud, m_impl, 0, 0);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Correct the p
|
|
|
|
|
+ U8* realptr = reinterpret_cast<U8*>(ptr) - m_headerSize;
|
|
|
|
|
|
|
|
- m_impl = nullptr;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // realptr should be inside the pool's preallocated memory
|
|
|
|
|
+ ANKI_ASSERT(realptr >= m_memory);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-PtrSize StackMemoryPool::getTotalSize() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->getTotalSize();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // Get block size
|
|
|
|
|
+ MemoryBlockHeader* header = reinterpret_cast<MemoryBlockHeader*>(realptr);
|
|
|
|
|
+ U32 size;
|
|
|
|
|
+ memcpy(&size, &header->m_size[0], sizeof(U32));
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-PtrSize StackMemoryPool::getAllocatedSize() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->getAllocatedSize();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // Check if the size is within limits
|
|
|
|
|
+ ANKI_ASSERT(realptr + size <= m_memory + m_memsize);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void* StackMemoryPool::allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- void* mem = m_impl->allocate(size, alignment);
|
|
|
|
|
|
|
+ // Atomic stuff
|
|
|
|
|
+ U8* expected = realptr + size;
|
|
|
|
|
+ U8* desired = realptr;
|
|
|
|
|
|
|
|
- if (mem == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGE("Out of memory");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // if(top == expected) {
|
|
|
|
|
+ // top = desired;
|
|
|
|
|
+ // exchange = true;
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // expected = top;
|
|
|
|
|
+ // exchange = false;
|
|
|
|
|
+ // }
|
|
|
|
|
+ Bool exchange = m_top.compare_exchange_strong(expected, desired);
|
|
|
|
|
|
|
|
- return mem;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // Decrease count
|
|
|
|
|
+ --m_allocationsCount;
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-Bool StackMemoryPool::free(void* ptr)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->free(ptr);
|
|
|
|
|
|
|
+ return exchange;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void StackMemoryPool::reset()
|
|
void StackMemoryPool::reset()
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- m_impl->reset();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // memory is nullptr if moved
|
|
|
|
|
+ ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-U32 StackMemoryPool::getUsersCount() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->m_refcount.load();
|
|
|
|
|
|
|
+#if ANKI_DEBUG
|
|
|
|
|
+ // Invalidate the memory
|
|
|
|
|
+ memset(m_memory, 0xCC, m_memsize);
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ m_top = m_memory;
|
|
|
|
|
+ m_allocationsCount = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
StackMemoryPool::Snapshot StackMemoryPool::getShapshot() const
|
|
StackMemoryPool::Snapshot StackMemoryPool::getShapshot() const
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->m_top.load();
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
+ return m_top.load();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
void StackMemoryPool::resetUsingSnapshot(Snapshot s)
|
|
void StackMemoryPool::resetUsingSnapshot(Snapshot s)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- ANKI_ASSERT(static_cast<U8*>(s) >= m_impl->m_memory);
|
|
|
|
|
- ANKI_ASSERT(static_cast<U8*>(s) < m_impl->m_memory + m_impl->m_memsize);
|
|
|
|
|
-
|
|
|
|
|
- m_impl->m_top.store(static_cast<U8*>(s));
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_memory != nullptr);
|
|
|
|
|
+ ANKI_ASSERT(static_cast<U8*>(s) >= m_memory);
|
|
|
|
|
+ ANKI_ASSERT(static_cast<U8*>(s) < m_memory + m_memsize);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-U32 StackMemoryPool::getAllocationsCount() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->m_allocationsCount.load();
|
|
|
|
|
|
|
+ m_top.store(static_cast<U8*>(s));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
@@ -658,514 +414,332 @@ U32 StackMemoryPool::getAllocationsCount() const
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-/// The hidden implementation of ChainMemoryPool
|
|
|
|
|
-class ChainMemoryPool::Implementation: public NonCopyable
|
|
|
|
|
|
|
+ChainMemoryPool::ChainMemoryPool()
|
|
|
|
|
+{}
|
|
|
|
|
+
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+ChainMemoryPool::~ChainMemoryPool()
|
|
|
{
|
|
{
|
|
|
-public:
|
|
|
|
|
- /// A chunk of memory
|
|
|
|
|
- class Chunk
|
|
|
|
|
|
|
+ Chunk* ch = m_headChunk;
|
|
|
|
|
+ while(ch)
|
|
|
{
|
|
{
|
|
|
- public:
|
|
|
|
|
- StackMemoryPool::Implementation m_pool;
|
|
|
|
|
-
|
|
|
|
|
- /// Used to identify if the chunk can be deleted
|
|
|
|
|
- U32 m_allocationsCount = 0;
|
|
|
|
|
-
|
|
|
|
|
- /// Next chunk in the list
|
|
|
|
|
- Chunk* m_next = nullptr;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- /// Refcount
|
|
|
|
|
- AtomicU32 m_refcount = {1};
|
|
|
|
|
-
|
|
|
|
|
- /// User allocation function
|
|
|
|
|
- AllocAlignedCallback m_allocCb;
|
|
|
|
|
-
|
|
|
|
|
- /// User allocation function data
|
|
|
|
|
- void* m_allocCbUserData;
|
|
|
|
|
-
|
|
|
|
|
- /// Alignment of allocations
|
|
|
|
|
- PtrSize m_alignmentBytes;
|
|
|
|
|
-
|
|
|
|
|
- /// The first chunk
|
|
|
|
|
- Chunk* m_headChunk = nullptr;
|
|
|
|
|
-
|
|
|
|
|
- /// Current chunk to allocate from
|
|
|
|
|
- Chunk* m_tailChunk = nullptr;
|
|
|
|
|
-
|
|
|
|
|
- /// Fast thread locking
|
|
|
|
|
- SpinLock m_lock;
|
|
|
|
|
-
|
|
|
|
|
- /// Chunk first chunk size
|
|
|
|
|
- PtrSize m_initSize;
|
|
|
|
|
-
|
|
|
|
|
- /// Chunk max size
|
|
|
|
|
- PtrSize m_maxSize;
|
|
|
|
|
-
|
|
|
|
|
- /// Chunk allocation method value
|
|
|
|
|
- U32 m_step;
|
|
|
|
|
|
|
+ Chunk* next = ch->m_next;
|
|
|
|
|
|
|
|
- /// Chunk allocation method
|
|
|
|
|
- ChainMemoryPool::ChunkGrowMethod m_method;
|
|
|
|
|
|
|
+ ch->~Chunk();
|
|
|
|
|
+ m_allocCb(m_allocCbUserData, ch, 0, 0);
|
|
|
|
|
|
|
|
- /// Allocations number.
|
|
|
|
|
- AtomicU32 m_allocationsCount = {0};
|
|
|
|
|
|
|
+ ch = next;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /// Construct
|
|
|
|
|
- Implementation(
|
|
|
|
|
- AllocAlignedCallback allocCb,
|
|
|
|
|
- void* allocCbUserData,
|
|
|
|
|
- PtrSize initialChunkSize,
|
|
|
|
|
- PtrSize maxChunkSize,
|
|
|
|
|
- ChainMemoryPool::ChunkGrowMethod chunkAllocStepMethod,
|
|
|
|
|
- PtrSize chunkAllocStep,
|
|
|
|
|
- PtrSize alignmentBytes)
|
|
|
|
|
- : m_allocCb(allocCb),
|
|
|
|
|
- m_allocCbUserData(allocCbUserData),
|
|
|
|
|
- m_alignmentBytes(alignmentBytes),
|
|
|
|
|
- m_initSize(initialChunkSize),
|
|
|
|
|
- m_maxSize(maxChunkSize),
|
|
|
|
|
- m_step((U32)chunkAllocStep),
|
|
|
|
|
- m_method(chunkAllocStepMethod)
|
|
|
|
|
|
|
+ if(m_lock)
|
|
|
{
|
|
{
|
|
|
ANKI_ASSERT(m_allocCb);
|
|
ANKI_ASSERT(m_allocCb);
|
|
|
-
|
|
|
|
|
- // Initial size should be > 0
|
|
|
|
|
- ANKI_ASSERT(m_initSize > 0 && "Wrong arg");
|
|
|
|
|
-
|
|
|
|
|
- // On fixed step should be 0
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_step == 0 && "Wrong arg");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // On fixed initial size is the same as the max
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_initSize == m_maxSize && "Wrong arg");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // On add and mul the max size should be greater than initial
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::ADD
|
|
|
|
|
- || m_method == ChainMemoryPool::ChunkGrowMethod::MULTIPLY)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_initSize < m_maxSize && "Wrong arg");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ m_lock->~SpinLock();
|
|
|
|
|
+ m_allocCb(m_allocCbUserData, m_lock, 0, 0);
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- /// Destroy
|
|
|
|
|
- ~Implementation()
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Error ChainMemoryPool::create(
|
|
|
|
|
+ AllocAlignedCallback allocCb,
|
|
|
|
|
+ void* allocCbUserData,
|
|
|
|
|
+ PtrSize initialChunkSize,
|
|
|
|
|
+ PtrSize maxChunkSize,
|
|
|
|
|
+ ChunkGrowMethod chunkAllocStepMethod,
|
|
|
|
|
+ PtrSize chunkAllocStep,
|
|
|
|
|
+ PtrSize alignmentBytes)
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(m_allocCb == nullptr);
|
|
|
|
|
+
|
|
|
|
|
+ // Set all values
|
|
|
|
|
+ m_allocCb = allocCb;
|
|
|
|
|
+ m_allocCbUserData = allocCbUserData;
|
|
|
|
|
+ m_alignmentBytes = alignmentBytes;
|
|
|
|
|
+ m_initSize = initialChunkSize;
|
|
|
|
|
+ m_maxSize = maxChunkSize;
|
|
|
|
|
+ m_step = chunkAllocStep;
|
|
|
|
|
+ m_method = chunkAllocStepMethod;
|
|
|
|
|
+
|
|
|
|
|
+ m_lock = reinterpret_cast<SpinLock*>(m_allocCb(
|
|
|
|
|
+ m_allocCbUserData, nullptr, sizeof(SpinLock), alignof(SpinLock)));
|
|
|
|
|
+ if(!m_lock)
|
|
|
{
|
|
{
|
|
|
- Chunk* ch = m_headChunk;
|
|
|
|
|
- while(ch)
|
|
|
|
|
- {
|
|
|
|
|
- Chunk* next = ch->m_next;
|
|
|
|
|
|
|
+ return ErrorCode::OUT_OF_MEMORY;
|
|
|
|
|
+ }
|
|
|
|
|
+ construct(m_lock);
|
|
|
|
|
|
|
|
- ch->~Chunk();
|
|
|
|
|
- m_allocCb(m_allocCbUserData, ch, 0, 0);
|
|
|
|
|
|
|
+ // Initial size should be > 0
|
|
|
|
|
+ ANKI_ASSERT(m_initSize > 0 && "Wrong arg");
|
|
|
|
|
|
|
|
- ch = next;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // On fixed step should be 0
|
|
|
|
|
+ if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(m_step == 0 && "Wrong arg");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-#if 0
|
|
|
|
|
- PtrSize computeNewChunkSize(PtrSize allocationSize)
|
|
|
|
|
|
|
+ // On fixed initial size is the same as the max
|
|
|
|
|
+ if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
{
|
|
{
|
|
|
- PtrSize crntMaxSize;
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
|
|
- {
|
|
|
|
|
- crntMaxSize = m_initSize;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // Get the size of the previous max chunk
|
|
|
|
|
- if(m_tailChunk != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- // Get the size of previous
|
|
|
|
|
- crntMaxSize = m_tailChunk->m_pool.getTotalSize();
|
|
|
|
|
-
|
|
|
|
|
- // Increase it
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::MULTIPLY)
|
|
|
|
|
- {
|
|
|
|
|
- crntMaxSize *= m_step;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_method
|
|
|
|
|
- == ChainMemoryPool::ChunkGrowMethod::ADD);
|
|
|
|
|
- crntMaxSize += m_step;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // No chunks. Choose initial size
|
|
|
|
|
-
|
|
|
|
|
- ANKI_ASSERT(m_headChunk == nullptr);
|
|
|
|
|
- crntMaxSize = m_initSize;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ANKI_ASSERT(crntMaxSize > 0);
|
|
|
|
|
-
|
|
|
|
|
- // Fix the size
|
|
|
|
|
- crntMaxSize = std::min(crntMaxSize, (PtrSize)m_maxSize);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- size = std::max(crntMaxSize, size) + 16;
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_initSize == m_maxSize && "Wrong arg");
|
|
|
}
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
|
|
|
|
- /// Create a new chunk
|
|
|
|
|
- Chunk* createNewChunk(PtrSize size)
|
|
|
|
|
|
|
+ // On add and mul the max size should be greater than initial
|
|
|
|
|
+ if(m_method == ChainMemoryPool::ChunkGrowMethod::ADD
|
|
|
|
|
+ || m_method == ChainMemoryPool::ChunkGrowMethod::MULTIPLY)
|
|
|
{
|
|
{
|
|
|
- //
|
|
|
|
|
- // Calculate preferred size
|
|
|
|
|
- //
|
|
|
|
|
-
|
|
|
|
|
- // Get the size of the next chunk
|
|
|
|
|
- PtrSize crntMaxSize;
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
|
|
- {
|
|
|
|
|
- crntMaxSize = m_initSize;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // Get the size of the previous max chunk
|
|
|
|
|
- if(m_tailChunk != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- // Get the size of previous
|
|
|
|
|
- crntMaxSize = m_tailChunk->m_pool.getTotalSize();
|
|
|
|
|
-
|
|
|
|
|
- // Increase it
|
|
|
|
|
- if(m_method == ChainMemoryPool::ChunkGrowMethod::MULTIPLY)
|
|
|
|
|
- {
|
|
|
|
|
- crntMaxSize *= m_step;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_method
|
|
|
|
|
- == ChainMemoryPool::ChunkGrowMethod::ADD);
|
|
|
|
|
- crntMaxSize += m_step;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- // No chunks. Choose initial size
|
|
|
|
|
-
|
|
|
|
|
- ANKI_ASSERT(m_headChunk == nullptr);
|
|
|
|
|
- crntMaxSize = m_initSize;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_initSize < m_maxSize && "Wrong arg");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- ANKI_ASSERT(crntMaxSize > 0);
|
|
|
|
|
|
|
+ return ErrorCode::NONE;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Fix the size
|
|
|
|
|
- crntMaxSize = min(crntMaxSize, (PtrSize)m_maxSize);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+void* ChainMemoryPool::allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(m_allocCb);
|
|
|
|
|
+ ANKI_ASSERT(size <= m_maxSize);
|
|
|
|
|
|
|
|
- size = max(crntMaxSize, size) + 16;
|
|
|
|
|
|
|
+ Chunk* ch;
|
|
|
|
|
+ void* mem = nullptr;
|
|
|
|
|
|
|
|
- //
|
|
|
|
|
- // Create the chunk
|
|
|
|
|
- //
|
|
|
|
|
- Chunk* chunk = (Chunk*)m_allocCb(
|
|
|
|
|
- m_allocCbUserData, nullptr, sizeof(Chunk), alignof(Chunk));
|
|
|
|
|
|
|
+ LockGuard<SpinLock> lock(*m_lock);
|
|
|
|
|
|
|
|
- if(chunk)
|
|
|
|
|
- {
|
|
|
|
|
- // Construct it
|
|
|
|
|
- construct(chunk);
|
|
|
|
|
- Error error = chunk->m_pool.create(
|
|
|
|
|
- m_allocCb, m_allocCbUserData, size, m_alignmentBytes);
|
|
|
|
|
-
|
|
|
|
|
- if(!error)
|
|
|
|
|
- {
|
|
|
|
|
- // Register it
|
|
|
|
|
- if(m_tailChunk)
|
|
|
|
|
- {
|
|
|
|
|
- m_tailChunk->m_next = chunk;
|
|
|
|
|
- m_tailChunk = chunk;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_headChunk == nullptr);
|
|
|
|
|
-
|
|
|
|
|
- m_headChunk = m_tailChunk = chunk;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- destruct(chunk);
|
|
|
|
|
- m_allocCb(m_allocCbUserData, chunk, 0, 0);
|
|
|
|
|
- chunk = nullptr;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGE("Out of memory");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return chunk;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Get chunk
|
|
|
|
|
+ ch = m_tailChunk;
|
|
|
|
|
|
|
|
- /// Allocate from chunk
|
|
|
|
|
- void* allocateFromChunk(Chunk* ch, PtrSize size, PtrSize alignment)
|
|
|
|
|
|
|
+ // Create new chunk if needed
|
|
|
|
|
+ if(ch == nullptr
|
|
|
|
|
+ || (mem = allocateFromChunk(ch, size, alignment)) == nullptr)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(ch);
|
|
|
|
|
- ANKI_ASSERT(size <= m_maxSize);
|
|
|
|
|
- void* mem = ch->m_pool.allocate(size, alignment);
|
|
|
|
|
|
|
+ // Create new chunk
|
|
|
|
|
+ ch = createNewChunk(size);
|
|
|
|
|
|
|
|
- if(mem)
|
|
|
|
|
- {
|
|
|
|
|
- ++ch->m_allocationsCount;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
|
|
+ // Chunk creation failed
|
|
|
|
|
+ if(ch == nullptr)
|
|
|
{
|
|
{
|
|
|
- // Chunk is full. Need a new one
|
|
|
|
|
|
|
+ return mem;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return mem;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Allocate memory
|
|
|
|
|
- void* allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
|
|
+ if(mem == nullptr)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(size <= m_maxSize);
|
|
|
|
|
-
|
|
|
|
|
- Chunk* ch;
|
|
|
|
|
- void* mem = nullptr;
|
|
|
|
|
|
|
+ mem = allocateFromChunk(ch, size, alignment);
|
|
|
|
|
+ ANKI_ASSERT(mem != nullptr && "The chunk should have space");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- m_lock.lock();
|
|
|
|
|
|
|
+ ++m_allocationsCount;
|
|
|
|
|
|
|
|
- // Get chunk
|
|
|
|
|
- ch = m_tailChunk;
|
|
|
|
|
|
|
+ return mem;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- // Create new chunk if needed
|
|
|
|
|
- if(ch == nullptr
|
|
|
|
|
- || (mem = allocateFromChunk(ch, size, alignment)) == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- // Create new chunk
|
|
|
|
|
- ch = createNewChunk(size);
|
|
|
|
|
|
|
+//==============================================================================
|
|
|
|
|
+Bool ChainMemoryPool::free(void* ptr)
|
|
|
|
|
+{
|
|
|
|
|
+ ANKI_ASSERT(m_allocCb);
|
|
|
|
|
+ if(ptr == nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // Chunk creation failed
|
|
|
|
|
- if(ch == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- m_lock.unlock();
|
|
|
|
|
- return mem;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ LockGuard<SpinLock> lock(*m_lock);
|
|
|
|
|
|
|
|
- if(mem == nullptr)
|
|
|
|
|
|
|
+ // Get the chunk that ptr belongs to
|
|
|
|
|
+ Chunk* chunk = m_headChunk;
|
|
|
|
|
+ Chunk* prevChunk = nullptr;
|
|
|
|
|
+ while(chunk)
|
|
|
|
|
+ {
|
|
|
|
|
+ const U8* from = chunk->m_pool.m_memory;
|
|
|
|
|
+ const U8* to = from + chunk->m_pool.m_memsize;
|
|
|
|
|
+ const U8* cptr = reinterpret_cast<const U8*>(ptr);
|
|
|
|
|
+ if(cptr >= from && cptr < to)
|
|
|
{
|
|
{
|
|
|
- mem = allocateFromChunk(ch, size, alignment);
|
|
|
|
|
- ANKI_ASSERT(mem != nullptr && "The chunk should have space");
|
|
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- m_lock.unlock();
|
|
|
|
|
- ++m_allocationsCount;
|
|
|
|
|
-
|
|
|
|
|
- return mem;
|
|
|
|
|
|
|
+ prevChunk = chunk;
|
|
|
|
|
+ chunk = chunk->m_next;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /// Free memory
|
|
|
|
|
- Bool free(void* ptr)
|
|
|
|
|
- {
|
|
|
|
|
- if(ptr == nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ANKI_ASSERT(chunk != nullptr
|
|
|
|
|
+ && "Not initialized or ptr is incorrect");
|
|
|
|
|
|
|
|
- m_lock.lock();
|
|
|
|
|
|
|
+ // Decrease the deallocation refcount and if it's zero delete the chunk
|
|
|
|
|
+ ANKI_ASSERT(chunk->m_allocationsCount > 0);
|
|
|
|
|
+ if(--chunk->m_allocationsCount == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Chunk is empty. Delete it
|
|
|
|
|
|
|
|
- // Get the chunk that ptr belongs to
|
|
|
|
|
- Chunk* chunk = m_headChunk;
|
|
|
|
|
- Chunk* prevChunk = nullptr;
|
|
|
|
|
- while(chunk)
|
|
|
|
|
|
|
+ if(prevChunk != nullptr)
|
|
|
{
|
|
{
|
|
|
- const U8* from = (const U8*)chunk->m_pool.getBaseAddress();
|
|
|
|
|
- const U8* to = from + chunk->m_pool.getTotalSize();
|
|
|
|
|
- const U8* cptr = (const U8*)ptr;
|
|
|
|
|
- if(cptr >= from && cptr < to)
|
|
|
|
|
- {
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- prevChunk = chunk;
|
|
|
|
|
- chunk = chunk->m_next;
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_headChunk != chunk);
|
|
|
|
|
+ prevChunk->m_next = chunk->m_next;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- ANKI_ASSERT(chunk != nullptr
|
|
|
|
|
- && "Not initialized or ptr is incorrect");
|
|
|
|
|
-
|
|
|
|
|
- // Decrease the deallocation refcount and if it's zero delete the chunk
|
|
|
|
|
- ANKI_ASSERT(chunk->m_allocationsCount > 0);
|
|
|
|
|
- if(--chunk->m_allocationsCount == 0)
|
|
|
|
|
|
|
+ if(chunk == m_headChunk)
|
|
|
{
|
|
{
|
|
|
- // Chunk is empty. Delete it
|
|
|
|
|
-
|
|
|
|
|
- if(prevChunk != nullptr)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(m_headChunk != chunk);
|
|
|
|
|
- prevChunk->m_next = chunk->m_next;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(chunk == m_headChunk)
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_ASSERT(prevChunk == nullptr);
|
|
|
|
|
- m_headChunk = chunk->m_next;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if(chunk == m_tailChunk)
|
|
|
|
|
- {
|
|
|
|
|
- m_tailChunk = prevChunk;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Finaly delete it
|
|
|
|
|
- chunk->~Chunk();
|
|
|
|
|
- m_allocCb(m_allocCbUserData, chunk, 0, 0);
|
|
|
|
|
|
|
+ ANKI_ASSERT(prevChunk == nullptr);
|
|
|
|
|
+ m_headChunk = chunk->m_next;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- m_lock.unlock();
|
|
|
|
|
-
|
|
|
|
|
- --m_allocationsCount;
|
|
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- PtrSize getAllocatedSize() const
|
|
|
|
|
- {
|
|
|
|
|
- PtrSize sum = 0;
|
|
|
|
|
- Chunk* ch = m_headChunk;
|
|
|
|
|
- while(ch)
|
|
|
|
|
|
|
+ if(chunk == m_tailChunk)
|
|
|
{
|
|
{
|
|
|
- sum += ch->m_pool.getAllocatedSize();
|
|
|
|
|
- ch = ch->m_next;
|
|
|
|
|
|
|
+ m_tailChunk = prevChunk;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return sum;
|
|
|
|
|
|
|
+ // Finaly delete it
|
|
|
|
|
+ chunk->~Chunk();
|
|
|
|
|
+ m_allocCb(m_allocCbUserData, chunk, 0, 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- PtrSize getChunksCount() const
|
|
|
|
|
- {
|
|
|
|
|
- PtrSize count = 0;
|
|
|
|
|
- Chunk* ch = m_headChunk;
|
|
|
|
|
- while(ch)
|
|
|
|
|
- {
|
|
|
|
|
- ++count;
|
|
|
|
|
- ch = ch->m_next;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ --m_allocationsCount;
|
|
|
|
|
|
|
|
- return count;
|
|
|
|
|
- }
|
|
|
|
|
-};
|
|
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-ChainMemoryPool& ChainMemoryPool::operator=(const ChainMemoryPool& other)
|
|
|
|
|
|
|
+PtrSize ChainMemoryPool::getChunksCount() const
|
|
|
{
|
|
{
|
|
|
- clear();
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_allocCb);
|
|
|
|
|
|
|
|
- if(other.m_impl)
|
|
|
|
|
|
|
+ PtrSize count = 0;
|
|
|
|
|
+ Chunk* ch = m_headChunk;
|
|
|
|
|
+ while(ch)
|
|
|
{
|
|
{
|
|
|
- m_impl = other.m_impl;
|
|
|
|
|
- ++m_impl->m_refcount;
|
|
|
|
|
|
|
+ ++count;
|
|
|
|
|
+ ch = ch->m_next;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return *this;
|
|
|
|
|
|
|
+ return count;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-Error ChainMemoryPool::create(
|
|
|
|
|
- AllocAlignedCallback alloc,
|
|
|
|
|
- void* allocUserData,
|
|
|
|
|
- PtrSize initialChunkSize,
|
|
|
|
|
- PtrSize maxChunkSize,
|
|
|
|
|
- ChunkGrowMethod chunkAllocStepMethod,
|
|
|
|
|
- PtrSize chunkAllocStep,
|
|
|
|
|
- PtrSize alignmentBytes)
|
|
|
|
|
|
|
+PtrSize ChainMemoryPool::getAllocatedSize() const
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(m_impl == nullptr);
|
|
|
|
|
-
|
|
|
|
|
- Error error = ErrorCode::NONE;
|
|
|
|
|
- m_impl = static_cast<Implementation*>(alloc(allocUserData, nullptr,
|
|
|
|
|
- sizeof(Implementation), alignof(Implementation)));
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_allocCb);
|
|
|
|
|
|
|
|
- if(m_impl)
|
|
|
|
|
|
|
+ PtrSize sum = 0;
|
|
|
|
|
+ Chunk* ch = m_headChunk;
|
|
|
|
|
+ while(ch)
|
|
|
{
|
|
{
|
|
|
- construct(
|
|
|
|
|
- m_impl,
|
|
|
|
|
- alloc, allocUserData,
|
|
|
|
|
- initialChunkSize, maxChunkSize, chunkAllocStepMethod,
|
|
|
|
|
- chunkAllocStep,
|
|
|
|
|
- alignmentBytes);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- ANKI_LOGE("Out of memory");
|
|
|
|
|
- error = ErrorCode::OUT_OF_MEMORY;
|
|
|
|
|
|
|
+ sum += ch->m_pool.getAllocatedSize();
|
|
|
|
|
+ ch = ch->m_next;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return error;
|
|
|
|
|
|
|
+ return sum;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-void ChainMemoryPool::clear()
|
|
|
|
|
|
|
+ChainMemoryPool::Chunk* ChainMemoryPool::createNewChunk(PtrSize size)
|
|
|
{
|
|
{
|
|
|
- if(m_impl)
|
|
|
|
|
|
|
+ //
|
|
|
|
|
+ // Calculate preferred size
|
|
|
|
|
+ //
|
|
|
|
|
+
|
|
|
|
|
+ // Get the size of the next chunk
|
|
|
|
|
+ PtrSize crntMaxSize;
|
|
|
|
|
+ if(m_method == ChainMemoryPool::ChunkGrowMethod::FIXED)
|
|
|
{
|
|
{
|
|
|
- U32 refcount = --m_impl->m_refcount;
|
|
|
|
|
|
|
+ crntMaxSize = m_initSize;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Get the size of the previous max chunk
|
|
|
|
|
+ if(m_tailChunk != nullptr)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Get the size of previous
|
|
|
|
|
+ crntMaxSize = m_tailChunk->m_pool.getTotalSize();
|
|
|
|
|
|
|
|
- if(refcount == 0)
|
|
|
|
|
|
|
+ // Increase it
|
|
|
|
|
+ if(m_method == ChainMemoryPool::ChunkGrowMethod::MULTIPLY)
|
|
|
|
|
+ {
|
|
|
|
|
+ crntMaxSize *= m_step;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(m_method
|
|
|
|
|
+ == ChainMemoryPool::ChunkGrowMethod::ADD);
|
|
|
|
|
+ crntMaxSize += m_step;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
- auto allocCb = m_impl->m_allocCb;
|
|
|
|
|
- auto ud = m_impl->m_allocCbUserData;
|
|
|
|
|
- ANKI_ASSERT(allocCb);
|
|
|
|
|
|
|
+ // No chunks. Choose initial size
|
|
|
|
|
|
|
|
- m_impl->~Implementation();
|
|
|
|
|
- allocCb(ud, m_impl, 0, 0);
|
|
|
|
|
|
|
+ ANKI_ASSERT(m_headChunk == nullptr);
|
|
|
|
|
+ crntMaxSize = m_initSize;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- m_impl = nullptr;
|
|
|
|
|
|
|
+ ANKI_ASSERT(crntMaxSize > 0);
|
|
|
|
|
+
|
|
|
|
|
+ // Fix the size
|
|
|
|
|
+ crntMaxSize = min(crntMaxSize, (PtrSize)m_maxSize);
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-void* ChainMemoryPool::allocate(PtrSize size, PtrSize alignment)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->allocate(size, alignment);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ size = max(crntMaxSize, size) + 16;
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-Bool ChainMemoryPool::free(void* ptr)
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->free(ptr);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ //
|
|
|
|
|
+ // Create the chunk
|
|
|
|
|
+ //
|
|
|
|
|
+ Chunk* chunk = (Chunk*)m_allocCb(
|
|
|
|
|
+ m_allocCbUserData, nullptr, sizeof(Chunk), alignof(Chunk));
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-PtrSize ChainMemoryPool::getChunksCount() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->getChunksCount();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ if(chunk)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Construct it
|
|
|
|
|
+ construct(chunk);
|
|
|
|
|
+ Error error = chunk->m_pool.create(
|
|
|
|
|
+ m_allocCb, m_allocCbUserData, size, m_alignmentBytes);
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-PtrSize ChainMemoryPool::getAllocatedSize() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->getAllocatedSize();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ if(!error)
|
|
|
|
|
+ {
|
|
|
|
|
+ chunk->m_pool.m_ignoreAllocationErrors = true;
|
|
|
|
|
|
|
|
-//==============================================================================
|
|
|
|
|
-U32 ChainMemoryPool::getUsersCount() const
|
|
|
|
|
-{
|
|
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->m_refcount.load();
|
|
|
|
|
|
|
+ // Register it
|
|
|
|
|
+ if(m_tailChunk)
|
|
|
|
|
+ {
|
|
|
|
|
+ m_tailChunk->m_next = chunk;
|
|
|
|
|
+ m_tailChunk = chunk;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_ASSERT(m_headChunk == nullptr);
|
|
|
|
|
+
|
|
|
|
|
+ m_headChunk = m_tailChunk = chunk;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ destruct(chunk);
|
|
|
|
|
+ m_allocCb(m_allocCbUserData, chunk, 0, 0);
|
|
|
|
|
+ chunk = nullptr;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ ANKI_LOGE("Out of memory");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return chunk;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
//==============================================================================
|
|
|
-U32 ChainMemoryPool::getAllocationsCount() const
|
|
|
|
|
|
|
+void* ChainMemoryPool::allocateFromChunk(
|
|
|
|
|
+ Chunk* ch, PtrSize size, PtrSize alignment)
|
|
|
{
|
|
{
|
|
|
- ANKI_ASSERT(m_impl != nullptr);
|
|
|
|
|
- return m_impl->m_allocationsCount.load();
|
|
|
|
|
|
|
+ ANKI_ASSERT(ch);
|
|
|
|
|
+ ANKI_ASSERT(size <= m_maxSize);
|
|
|
|
|
+ void* mem = ch->m_pool.allocate(size, alignment);
|
|
|
|
|
+
|
|
|
|
|
+ if(mem)
|
|
|
|
|
+ {
|
|
|
|
|
+ ++ch->m_allocationsCount;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // Chunk is full. Need a new one
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return mem;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // end namespace anki
|
|
} // end namespace anki
|