2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/common/fixed-size-memory-pool.h>
22 #include <dali/devel-api/threading/mutex.h>
23 #include <dali/public-api/common/dali-common.h>
30 * @brief Private implementation class
32 struct FixedSizeMemoryPool::Impl
35 * @brief Struct to represent a block of memory from which allocations can be made.
37 * The block forms a linked list.
41 void* blockMemory; ///< The allocated memory from which allocations can be made
42 Block* nextBlock; ///< The next block in the linked list
44 SizeType mBlockSize; ///< Size of the block in bytes
47 * @brief Construct a new block with given size
49 * @param size The size of the memory block to allocate in bytes. Must be non-zero.
58 blockMemory = ::operator new(size);
59 DALI_ASSERT_ALWAYS(blockMemory && "Out of memory");
67 ::operator delete(blockMemory);
72 Block(const Block& block);
75 Block& operator=(const Block& block);
81 Impl(SizeType fixedSize, SizeType initialCapacity, SizeType maximumBlockCapacity)
83 mFixedSize(fixedSize),
84 mMemoryBlocks(initialCapacity * mFixedSize),
85 mMaximumBlockCapacity(maximumBlockCapacity),
86 mCurrentBlock(&mMemoryBlocks),
87 mCurrentBlockCapacity(initialCapacity),
89 mDeletedObjects(nullptr)
91 // We need enough room to store the deleted list in the data
92 DALI_ASSERT_DEBUG(mFixedSize >= sizeof(void*));
100 // Clean up memory block linked list (mMemoryBlocks will be auto-destroyed by its destructor)
101 Block* block = mMemoryBlocks.nextBlock;
104 Block* nextBlock = block->nextBlock;
111 * @brief Allocate a new block for allocating memory from
113 void AllocateNewBlock()
115 // Double capacity for the new block
116 SizeType size = mCurrentBlockCapacity * 2;
117 if(size > mMaximumBlockCapacity || size < mCurrentBlockCapacity) // Check for overflow of size type
119 size = mMaximumBlockCapacity;
122 mCurrentBlockCapacity = size;
125 Block* block = new Block(mCurrentBlockCapacity * mFixedSize);
126 mCurrentBlock->nextBlock = block; // Add to end of linked list
127 mCurrentBlock = block;
129 mCurrentBlockSize = 0;
134 * @brief check the memory being free'd exists inside the memory pool
135 * @param[in] memory address of object to remove
137 void CheckMemoryIsInsidePool(const void* const memory)
139 bool inRange = false;
140 const Block* block = &mMemoryBlocks;
144 const void* const endOfBlock = reinterpret_cast<char*>(block->blockMemory) + block->mBlockSize;
146 if((memory >= block->blockMemory) && (memory < (endOfBlock)))
151 block = block->nextBlock;
153 DALI_ASSERT_DEBUG(inRange && "Freeing memory that does not exist in memory pool");
157 Mutex mMutex; ///< Mutex for thread-safe allocation and deallocation
159 SizeType mFixedSize; ///< The size of each allocation in bytes
161 Block mMemoryBlocks; ///< Linked list of allocated memory blocks
162 SizeType mMaximumBlockCapacity; ///< The maximum allowed capacity of allocations in a new memory block
164 Block* mCurrentBlock; ///< Pointer to the active block
165 SizeType mCurrentBlockCapacity; ///< The maximum number of allocations that can be allocated for the current block
166 SizeType mCurrentBlockSize; ///< The number of allocations allocated to the current block
168 void* mDeletedObjects; ///< Pointer to the head of the list of deleted objects. The addresses are stored in the allocated memory blocks.
171 FixedSizeMemoryPool::FixedSizeMemoryPool(SizeType fixedSize, SizeType initialCapacity, SizeType maximumBlockCapacity)
173 mImpl = new Impl(fixedSize, initialCapacity, maximumBlockCapacity);
176 FixedSizeMemoryPool::~FixedSizeMemoryPool()
181 void* FixedSizeMemoryPool::Allocate()
183 // First, recycle deleted objects
184 if(mImpl->mDeletedObjects)
186 void* recycled = mImpl->mDeletedObjects;
187 mImpl->mDeletedObjects = *(reinterpret_cast<void**>(mImpl->mDeletedObjects)); // Pop head off front of deleted objects list
191 // Check if current block is full
192 if(mImpl->mCurrentBlockSize >= mImpl->mCurrentBlockCapacity)
194 mImpl->AllocateNewBlock();
197 // Placement new the object in block memory
198 uint8_t* objectAddress = static_cast<uint8_t*>(mImpl->mCurrentBlock->blockMemory);
199 objectAddress += mImpl->mCurrentBlockSize * mImpl->mFixedSize;
200 mImpl->mCurrentBlockSize++;
202 return objectAddress;
205 void FixedSizeMemoryPool::Free(void* memory)
210 mImpl->CheckMemoryIsInsidePool(memory);
213 // Add memory to head of deleted objects list. Store next address in the same memory space as the old object.
214 *(reinterpret_cast<void**>(memory)) = mImpl->mDeletedObjects;
215 mImpl->mDeletedObjects = memory;
219 void* FixedSizeMemoryPool::AllocateThreadSafe()
221 Mutex::ScopedLock lock(mImpl->mMutex);
225 void FixedSizeMemoryPool::FreeThreadSafe(void* memory)
229 Mutex::ScopedLock lock(mImpl->mMutex);
234 } // namespace Internal