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>
32 * @brief Private implementation class
34 struct FixedSizeMemoryPool::Impl
37 * @brief Struct to represent a block of memory from which allocations can be made.
39 * The block forms a linked list.
43 void* blockMemory; ///< The allocated memory from which allocations can be made
44 Block* nextBlock; ///< The next block in the linked list
46 SizeType mBlockSize; ///< Size of the block in bytes
49 * @brief Construct a new block with given size
51 * @param size The size of the memory block to allocate in bytes. Must be non-zero.
53 Block( SizeType size )
59 blockMemory = ::operator new( size );
60 DALI_ASSERT_ALWAYS( blockMemory && "Out of memory" );
68 ::operator delete( blockMemory );
73 Block( const Block& block );
76 Block& operator=( const Block& block );
82 Impl( SizeType fixedSize, SizeType initialCapacity, SizeType maximumBlockCapacity )
84 mFixedSize( fixedSize ),
85 mMemoryBlocks( initialCapacity * mFixedSize ),
86 mMaximumBlockCapacity( maximumBlockCapacity ),
87 mCurrentBlock( &mMemoryBlocks ),
88 mCurrentBlockCapacity( initialCapacity ),
89 mCurrentBlockSize( 0 ),
90 mDeletedObjects( NULL )
92 // We need enough room to store the deleted list in the data
93 DALI_ASSERT_DEBUG( mFixedSize >= sizeof( void* ) );
101 // Clean up memory block linked list (mMemoryBlocks will be auto-destroyed by its destructor)
102 Block* block = mMemoryBlocks.nextBlock;
105 Block* nextBlock = block->nextBlock;
112 * @brief Allocate a new block for allocating memory from
114 void AllocateNewBlock()
116 // Double capacity for the new block
117 SizeType size = mCurrentBlockCapacity * 2;
118 if( size > mMaximumBlockCapacity || size < mCurrentBlockCapacity ) // Check for overflow of size type
120 size = mMaximumBlockCapacity;
123 mCurrentBlockCapacity = size;
126 Block* block = new Block( mCurrentBlockCapacity * mFixedSize );
127 mCurrentBlock->nextBlock = block; // Add to end of linked list
128 mCurrentBlock = block;
130 mCurrentBlockSize = 0;
135 * @brief check the memory being free'd exists inside the memory pool
136 * @param[in] memory address of object to remove
138 void CheckMemoryIsInsidePool( const void* const memory )
140 bool inRange = false;
141 const Block* block = &mMemoryBlocks;
145 const void* const endOfBlock = reinterpret_cast<char *>( block->blockMemory )+ block->mBlockSize;
147 if( ( memory >= block->blockMemory ) && ( memory < (endOfBlock) ) )
152 block = block->nextBlock;
154 DALI_ASSERT_DEBUG( inRange && "Freeing memory that does not exist in memory pool" );
158 Mutex mMutex; ///< Mutex for thread-safe allocation and deallocation
160 SizeType mFixedSize; ///< The size of each allocation in bytes
162 Block mMemoryBlocks; ///< Linked list of allocated memory blocks
163 SizeType mMaximumBlockCapacity; ///< The maximum allowed capacity of allocations in a new memory block
165 Block* mCurrentBlock; ///< Pointer to the active block
166 SizeType mCurrentBlockCapacity; ///< The maximum number of allocations that can be allocated for the current block
167 SizeType mCurrentBlockSize; ///< The number of allocations allocated to the current block
169 void* mDeletedObjects; ///< Pointer to the head of the list of deleted objects. The addresses are stored in the allocated memory blocks.
172 FixedSizeMemoryPool::FixedSizeMemoryPool( SizeType fixedSize, SizeType initialCapacity, SizeType maximumBlockCapacity )
174 mImpl = new Impl( fixedSize, initialCapacity, maximumBlockCapacity );
177 FixedSizeMemoryPool::~FixedSizeMemoryPool()
182 void* FixedSizeMemoryPool::Allocate()
184 // First, recycle deleted objects
185 if( mImpl->mDeletedObjects )
187 void* recycled = mImpl->mDeletedObjects;
188 mImpl->mDeletedObjects = *( reinterpret_cast< void** >( mImpl->mDeletedObjects ) ); // Pop head off front of deleted objects list
192 // Check if current block is full
193 if( mImpl->mCurrentBlockSize >= mImpl->mCurrentBlockCapacity )
195 mImpl->AllocateNewBlock();
198 // Placement new the object in block memory
199 uint8_t* objectAddress = static_cast< uint8_t* >( mImpl->mCurrentBlock->blockMemory );
200 objectAddress += mImpl->mCurrentBlockSize * mImpl->mFixedSize;
201 mImpl->mCurrentBlockSize++;
203 return objectAddress;
206 void FixedSizeMemoryPool::Free( void* memory )
209 mImpl->CheckMemoryIsInsidePool( memory );
212 // Add memory to head of deleted objects list. Store next address in the same memory space as the old object.
213 *( reinterpret_cast< void** >( memory ) ) = mImpl->mDeletedObjects;
214 mImpl->mDeletedObjects = memory;
217 void* FixedSizeMemoryPool::AllocateThreadSafe()
219 Mutex::ScopedLock lock( mImpl->mMutex );
223 void FixedSizeMemoryPool::FreeThreadSafe( void* memory )
225 Mutex::ScopedLock lock( mImpl->mMutex );
230 } // namespace Internal