Home | History | Annotate | Download | only in depool
      1 /*-------------------------------------------------------------------------
      2  * drawElements Memory Pool Library
      3  * --------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Memory pool management.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "deMemPool.h"
     25 #include "deMemory.h"
     26 #include "deInt32.h"
     27 
     28 #if defined(DE_SUPPORT_FAILING_POOL_ALLOC)
     29 #	include "deRandom.h"
     30 #endif
     31 
     32 #include <stdlib.h>
     33 #include <string.h>
     34 
     35 enum
     36 {
     37 	INITIAL_PAGE_SIZE		= 128,		/*!< Size for the first allocated memory page.			*/
     38 	MAX_PAGE_SIZE			= 8096,		/*!< Maximum size for a memory page.					*/
     39 	MEM_PAGE_BASE_ALIGN		= 4			/*!< Base alignment guarantee for mem page data ptr.	*/
     40 };
     41 
     42 typedef struct MemPage_s MemPage;
     43 
     44 /*--------------------------------------------------------------------*//*!
     45  * \internal
     46  * \brief Memory page header.
     47  *
     48  * Represent a page of memory allocate by a memory pool.
     49  *//*--------------------------------------------------------------------*/
     50 struct MemPage_s
     51 {
     52 	int			capacity;
     53 	int			bytesAllocated;
     54 
     55 	MemPage*	nextPage;
     56 };
     57 
     58 #if defined(DE_SUPPORT_DEBUG_POOLS)
     59 typedef struct DebugAlloc_s DebugAlloc;
     60 
     61 struct DebugAlloc_s
     62 {
     63 	void*			memPtr;
     64 	DebugAlloc*		next;
     65 };
     66 #endif
     67 
     68 /*--------------------------------------------------------------------*//*!
     69  * \brief Memory pool.
     70  *
     71  * A pool of memory from which individual memory allocations can be made.
     72  * The memory pools don't have a freeing operation for individual allocations,
     73  * but rather all of the memory allocated from a pool is freed when the pool
     74  * is destroyed.
     75  *
     76  * The pools can be arranged into a hierarchy. If a pool with children is
     77  * destroyed, all of the children are first recursively destroyed and then
     78  * the pool itself.
     79  *
     80  * The memory pools support a feature where individual allocations can be
     81  * made to simulate failure (i.e., return null). This can be enabled by
     82  * creating the root pool with the deMemPool_createFailingRoot() function.
     83  * When the feature is enabled, also creation of sub-pools occasionally
     84  * fails.
     85  *//*--------------------------------------------------------------------*/
     86 struct deMemPool_s
     87 {
     88 	deUint32		flags;				/*!< Flags.											*/
     89 	deMemPool*		parent;				/*!< Pointer to parent (null for root pools).		*/
     90 	deMemPoolUtil*	util;				/*!< Utilities (callbacks etc.).					*/
     91 	int				numChildren;		/*!< Number of child pools.							*/
     92 	deMemPool*		firstChild;			/*!< Pointer to first child pool in linked list.	*/
     93 	deMemPool*		prevPool;			/*!< Previous pool in parent's linked list.			*/
     94 	deMemPool*		nextPool;			/*!< Next pool in parent's linked list.				*/
     95 
     96 	MemPage*		currentPage;		/*!< Current memory page from which to allocate.	*/
     97 
     98 #if defined(DE_SUPPORT_FAILING_POOL_ALLOC)
     99 	deBool			allowFailing;		/*!< Is allocation failure simulation enabled?		*/
    100 	deRandom		failRandom;			/*!< RNG for failing allocations.					*/
    101 #endif
    102 #if defined(DE_SUPPORT_DEBUG_POOLS)
    103 	deBool			enableDebugAllocs;	/*!< If true, always allocates using deMalloc().	*/
    104 	DebugAlloc*		debugAllocListHead;	/*!< List of allocation in debug mode.				*/
    105 
    106 	int				lastAllocatedIndex;	/*!< Index of last allocated pool (rootPool only).	*/
    107 	int				allocIndex;			/*!< Allocation index (running counter).			*/
    108 #endif
    109 #if defined(DE_SUPPORT_POOL_MEMORY_TRACKING)
    110 	int				maxMemoryAllocated;	/*!< Maximum amount of memory allocated from pools.	*/
    111 	int				maxMemoryCapacity;	/*!< Maximum amount of memory allocated for pools.	*/
    112 #endif
    113 };
    114 
    115 /*--------------------------------------------------------------------*//*!
    116  * \internal
    117  * \brief Initialize a memory page.
    118  * \param page		Memory page to initialize.
    119  * \param capacity	Capacity allocated for the memory page.
    120  *//*--------------------------------------------------------------------*/
    121 static void MemPage_init (MemPage* page, int capacity)
    122 {
    123 	memset(page, 0, sizeof(MemPage));
    124 #if defined(DE_DEBUG)
    125 	memset(page + 1, 0xCD, capacity);
    126 #endif
    127 	page->capacity = capacity;
    128 }
    129 
    130 /*--------------------------------------------------------------------*//*!
    131  * \internal
    132  * \brief Create a new memory page.
    133  * \param capacity	Capacity for the memory page.
    134  * \return The created memory page (or null on failure).
    135  *//*--------------------------------------------------------------------*/
    136 static MemPage* MemPage_create (int capacity)
    137 {
    138 	MemPage* page = (MemPage*)deMalloc(sizeof(MemPage) + capacity);
    139 	if (!page)
    140 		return DE_NULL;
    141 
    142 	DE_ASSERT(deIsAlignedPtr(page+1, MEM_PAGE_BASE_ALIGN));
    143 
    144 	MemPage_init(page, capacity);
    145 	return page;
    146 }
    147 
    148 /*--------------------------------------------------------------------*//*!
    149  * \internal
    150  * \brief Destroy a memory page.
    151  * \param page	Memory page to destroy.
    152  *//*--------------------------------------------------------------------*/
    153 static void MemPage_destroy (MemPage* page)
    154 {
    155 #if defined(DE_DEBUG)
    156 	/* Fill with garbage to hopefully catch dangling pointer bugs easier. */
    157 	deUint8* dataPtr = (deUint8*)(page + 1);
    158 	memset(dataPtr, 0xCD, page->capacity);
    159 #endif
    160 	deFree(page);
    161 }
    162 
    163 /*--------------------------------------------------------------------*//*!
    164  * \internal
    165  * \brief Internal function for creating a new memory pool.
    166  * \param parent	Parent pool (may be null).
    167  * \return The created memory pool (or null on failure).
    168  *//*--------------------------------------------------------------------*/
    169 static deMemPool* createPoolInternal (deMemPool* parent)
    170 {
    171 	deMemPool*	pool;
    172 	MemPage*	initialPage;
    173 
    174 #if defined(DE_SUPPORT_FAILING_POOL_ALLOC)
    175 	if (parent && parent->allowFailing)
    176 	{
    177 		if ((deRandom_getUint32(&parent->failRandom) & 16383) <= 15)
    178 			return DE_NULL;
    179 	}
    180 #endif
    181 
    182 	/* Init first page. */
    183 	initialPage = MemPage_create(INITIAL_PAGE_SIZE);
    184 	if (!initialPage)
    185 		return DE_NULL;
    186 
    187 	/* Alloc pool from initial page. */
    188 	DE_ASSERT((int)sizeof(deMemPool) <= initialPage->capacity);
    189 	pool = (deMemPool*)(initialPage + 1);
    190 	initialPage->bytesAllocated += (int)sizeof(deMemPool);
    191 
    192 	memset(pool, 0, sizeof(deMemPool));
    193 	pool->currentPage = initialPage;
    194 
    195 	/* Register to parent. */
    196 	pool->parent = parent;
    197 	if (parent)
    198 	{
    199 		parent->numChildren++;
    200 		if (parent->firstChild) parent->firstChild->prevPool = pool;
    201 		pool->nextPool = parent->firstChild;
    202 		parent->firstChild = pool;
    203 	}
    204 
    205 	/* Get utils from parent. */
    206 	pool->util = parent ? parent->util : DE_NULL;
    207 
    208 #if defined(DE_SUPPORT_FAILING_POOL_ALLOC)
    209 	pool->allowFailing = parent ? parent->allowFailing : DE_FALSE;
    210 	deRandom_init(&pool->failRandom, parent ? deRandom_getUint32(&parent->failRandom) : 0x1234abcd);
    211 #endif
    212 
    213 #if defined(DE_SUPPORT_DEBUG_POOLS)
    214 	pool->enableDebugAllocs		= parent ? parent->enableDebugAllocs : DE_FALSE;
    215 	pool->debugAllocListHead	= DE_NULL;
    216 
    217 	/* Pool allocation index. */
    218 	{
    219 		deMemPool* root = pool;
    220 		while (root->parent)
    221 			root = root->parent;
    222 
    223 		if (pool == root)
    224 			root->lastAllocatedIndex = 0;
    225 
    226 		pool->allocIndex = ++root->lastAllocatedIndex;
    227 
    228 		/* \note Put the index of leaking pool here and add a breakpoint to catch leaks easily. */
    229 /*		if (pool->allocIndex == 51)
    230 			root = root;*/
    231 	}
    232 #endif
    233 
    234 	return pool;
    235 }
    236 
    237 /*--------------------------------------------------------------------*//*!
    238  * \brief Create a new root memory pool.
    239  * \return The created memory pool (or null on failure).
    240  *//*--------------------------------------------------------------------*/
    241 deMemPool* deMemPool_createRoot	(const deMemPoolUtil* util, deUint32 flags)
    242 {
    243 	deMemPool* pool = createPoolInternal(DE_NULL);
    244 	if (!pool)
    245 		return DE_NULL;
    246 #if defined(DE_SUPPORT_FAILING_POOL_ALLOC)
    247 	if (flags & DE_MEMPOOL_ENABLE_FAILING_ALLOCS)
    248 		pool->allowFailing = DE_TRUE;
    249 #endif
    250 #if defined(DE_SUPPORT_DEBUG_POOLS)
    251 	if (flags & DE_MEMPOOL_ENABLE_DEBUG_ALLOCS)
    252 	{
    253 		pool->enableDebugAllocs		= DE_TRUE;
    254 		pool->debugAllocListHead	= DE_NULL;
    255 	}
    256 #endif
    257 	DE_UNREF(flags); /* in case no debug features enabled */
    258 
    259 	/* Get copy of utilities. */
    260 	if (util)
    261 	{
    262 		deMemPoolUtil* utilCopy = DE_POOL_NEW(pool, deMemPoolUtil);
    263 		DE_ASSERT(util->allocFailCallback);
    264 		if (!utilCopy)
    265 		{
    266 			deMemPool_destroy(pool);
    267 			return DE_NULL;
    268 		}
    269 
    270 		memcpy(utilCopy, util, sizeof(deMemPoolUtil));
    271 		pool->util = utilCopy;
    272 	}
    273 
    274 	return pool;
    275 }
    276 
    277 /*--------------------------------------------------------------------*//*!
    278  * \brief Create a sub-pool for an existing memory pool.
    279  * \return The created memory pool (or null on failure).
    280  *//*--------------------------------------------------------------------*/
    281 deMemPool* deMemPool_create (deMemPool* parent)
    282 {
    283 	deMemPool* pool;
    284 	DE_ASSERT(parent);
    285 	pool = createPoolInternal(parent);
    286 	if (!pool && parent->util)
    287 		parent->util->allocFailCallback(parent->util->userPointer);
    288 	return pool;
    289 }
    290 
    291 /*--------------------------------------------------------------------*//*!
    292  * \brief Destroy a memory pool.
    293  * \param pool	Pool to be destroyed.
    294  *
    295  * Frees all the memory allocated from the pool. Also destroyed any child
    296  * pools that the pool has (recursively).
    297  *//*--------------------------------------------------------------------*/
    298 void deMemPool_destroy (deMemPool* pool)
    299 {
    300 	deMemPool* iter;
    301 	deMemPool* iterNext;
    302 
    303 #if defined(DE_SUPPORT_POOL_MEMORY_TRACKING)
    304 	/* Update memory consumption statistics. */
    305 	if (pool->parent)
    306 	{
    307 		deMemPool* root = pool->parent;
    308 		while (root->parent)
    309 			root = root->parent;
    310 		root->maxMemoryAllocated	= deMax32(root->maxMemoryAllocated, deMemPool_getNumAllocatedBytes(root, DE_TRUE));
    311 		root->maxMemoryCapacity		= deMax32(root->maxMemoryCapacity, deMemPool_getCapacity(root, DE_TRUE));
    312 	}
    313 #endif
    314 
    315 	/* Destroy all children. */
    316 	iter = pool->firstChild;
    317 	while (iter)
    318 	{
    319 		iterNext = iter->nextPool;
    320 		deMemPool_destroy(iter);
    321 		iter = iterNext;
    322 	}
    323 
    324 	DE_ASSERT(pool->numChildren == 0);
    325 
    326 	/* Update pointers. */
    327 	if (pool->prevPool) pool->prevPool->nextPool = pool->nextPool;
    328 	if (pool->nextPool) pool->nextPool->prevPool = pool->prevPool;
    329 
    330 	if (pool->parent)
    331 	{
    332 		deMemPool* parent = pool->parent;
    333 		if (parent->firstChild == pool)
    334 			parent->firstChild = pool->nextPool;
    335 
    336 		parent->numChildren--;
    337 		DE_ASSERT(parent->numChildren >= 0);
    338 	}
    339 
    340 #if defined(DE_SUPPORT_DEBUG_POOLS)
    341 	/* Free all debug allocations. */
    342 	if (pool->enableDebugAllocs)
    343 	{
    344 		DebugAlloc* alloc	= pool->debugAllocListHead;
    345 		DebugAlloc* next;
    346 
    347 		while (alloc)
    348 		{
    349 			next = alloc->next;
    350 			deAlignedFree(alloc->memPtr);
    351 			deFree(alloc);
    352 			alloc = next;
    353 		}
    354 
    355 		pool->debugAllocListHead = DE_NULL;
    356 	}
    357 #endif
    358 
    359 	/* Free pages. */
    360 	/* \note Pool itself is allocated from first page, so we must not touch the pool after freeing the page! */
    361 	{
    362 		MemPage* page = pool->currentPage;
    363 		MemPage* nextPage;
    364 
    365 		while (page)
    366 		{
    367 			nextPage = page->nextPage;
    368 			MemPage_destroy(page);
    369 			page = nextPage;
    370 		}
    371 	}
    372 }
    373 
    374 /*--------------------------------------------------------------------*//*!
    375  * \brief Get the number of children for a pool.
    376  * \return The number of (immediate) child pools a memory pool has.
    377  *//*--------------------------------------------------------------------*/
    378 int deMemPool_getNumChildren (const deMemPool* pool)
    379 {
    380 	return pool->numChildren;
    381 }
    382 
    383 /*--------------------------------------------------------------------*//*!
    384  * \brief Get the number of bytes allocated (by the user) from the pool.
    385  * \param pool		Pool pointer.
    386  * \param recurse	Is operation recursive to child pools?
    387  * \return The number of bytes allocated by the pool (including child pools
    388  *		   if 'recurse' is true).
    389  *//*--------------------------------------------------------------------*/
    390 int deMemPool_getNumAllocatedBytes (const deMemPool* pool, deBool recurse)
    391 {
    392 	int			numAllocatedBytes = 0;
    393 	MemPage*	memPage;
    394 
    395 	for (memPage = pool->currentPage; memPage; memPage = memPage->nextPage)
    396 		numAllocatedBytes += memPage->bytesAllocated;
    397 
    398 	if (recurse)
    399 	{
    400 		deMemPool* child;
    401 		for (child = pool->firstChild; child; child = child->nextPool)
    402 			numAllocatedBytes += deMemPool_getNumAllocatedBytes(child, DE_TRUE);
    403 	}
    404 
    405 	return numAllocatedBytes;
    406 }
    407 
    408 int deMemPool_getCapacity (const deMemPool* pool, deBool recurse)
    409 {
    410 	int			numCapacityBytes = 0;
    411 	MemPage*	memPage;
    412 
    413 	for (memPage = pool->currentPage; memPage; memPage = memPage->nextPage)
    414 		numCapacityBytes += memPage->capacity;
    415 
    416 	if (recurse)
    417 	{
    418 		deMemPool* child;
    419 		for (child = pool->firstChild; child; child = child->nextPool)
    420 			numCapacityBytes += deMemPool_getCapacity(child, DE_TRUE);
    421 	}
    422 
    423 	return numCapacityBytes;
    424 }
    425 
    426 DE_INLINE void* deMemPool_allocInternal (deMemPool* pool, int numBytes, deUint32 alignBytes)
    427 {
    428 	MemPage* curPage = pool->currentPage;
    429 
    430 #if defined(DE_SUPPORT_FAILING_POOL_ALLOC)
    431 	if (pool->allowFailing)
    432 	{
    433 		if ((deRandom_getUint32(&pool->failRandom) & 16383) <= 15)
    434 			return DE_NULL;
    435 	}
    436 #endif
    437 
    438 #if defined(DE_SUPPORT_DEBUG_POOLS)
    439 	if (pool->enableDebugAllocs)
    440 	{
    441 		DebugAlloc*	header	= DE_NEW(DebugAlloc);
    442 		void*		ptr		= deAlignedMalloc(numBytes, alignBytes);
    443 
    444 		if (!header || !ptr)
    445 		{
    446 			deFree(header);
    447 			deAlignedFree(ptr);
    448 			return DE_NULL;
    449 		}
    450 
    451 		header->memPtr	= ptr;
    452 		header->next	= pool->debugAllocListHead;
    453 		pool->debugAllocListHead = header;
    454 
    455 		return ptr;
    456 	}
    457 #endif
    458 
    459 	DE_ASSERT(curPage);
    460 	DE_ASSERT(deIsPowerOfTwo32(alignBytes));
    461 	{
    462 		void*	curPagePtr		= (void*)((deUint8*)(curPage + 1) + curPage->bytesAllocated);
    463 		void*	alignedPtr		= deAlignPtr(curPagePtr, alignBytes);
    464 		int		alignPadding	= (int)((deUintptr)alignedPtr - (deUintptr)curPagePtr);
    465 
    466 		if (numBytes + alignPadding > curPage->capacity - curPage->bytesAllocated)
    467 		{
    468 			/* Does not fit to current page. */
    469 			int		maxAlignPadding		= deMax32(0, alignBytes-MEM_PAGE_BASE_ALIGN);
    470 			int		newPageCapacity		= deMax32(deMin32(2*curPage->capacity, MAX_PAGE_SIZE), numBytes+maxAlignPadding);
    471 
    472 			curPage = MemPage_create(newPageCapacity);
    473 			if (!curPage)
    474 				return DE_NULL;
    475 
    476 			curPage->nextPage	= pool->currentPage;
    477 			pool->currentPage	= curPage;
    478 
    479 			DE_ASSERT(curPage->bytesAllocated == 0);
    480 
    481 			curPagePtr			= (void*)(curPage + 1);
    482 			alignedPtr			= deAlignPtr(curPagePtr, alignBytes);
    483 			alignPadding		= (int)((deUintptr)alignedPtr - (deUintptr)curPagePtr);
    484 
    485 			DE_ASSERT(numBytes + alignPadding <= curPage->capacity);
    486 		}
    487 
    488 		curPage->bytesAllocated += numBytes+alignPadding;
    489 		return alignedPtr;
    490 	}
    491 }
    492 
    493 /*--------------------------------------------------------------------*//*!
    494  * \brief Allocate memory from a pool.
    495  * \param pool		Memory pool to allocate from.
    496  * \param numBytes	Number of bytes to allocate.
    497  * \return Pointer to the allocate memory (or null on failure).
    498  *//*--------------------------------------------------------------------*/
    499 void* deMemPool_alloc (deMemPool* pool, int numBytes)
    500 {
    501 	void* ptr;
    502 	DE_ASSERT(pool);
    503 	DE_ASSERT(numBytes > 0);
    504 	ptr = deMemPool_allocInternal(pool, numBytes, DE_POOL_DEFAULT_ALLOC_ALIGNMENT);
    505 	if (!ptr && pool->util)
    506 		pool->util->allocFailCallback(pool->util->userPointer);
    507 	return ptr;
    508 }
    509 
    510 /*--------------------------------------------------------------------*//*!
    511  * \brief Allocate aligned memory from a pool.
    512  * \param pool			Memory pool to allocate from.
    513  * \param numBytes		Number of bytes to allocate.
    514  * \param alignBytes	Required alignment in bytes, must be power of two.
    515  * \return Pointer to the allocate memory (or null on failure).
    516  *//*--------------------------------------------------------------------*/
    517 void* deMemPool_alignedAlloc (deMemPool* pool, int numBytes, deUint32 alignBytes)
    518 {
    519 	void* ptr;
    520 	DE_ASSERT(pool);
    521 	DE_ASSERT(numBytes > 0);
    522 	DE_ASSERT(deIsPowerOfTwo32((int)alignBytes));
    523 	ptr = deMemPool_allocInternal(pool, numBytes, alignBytes);
    524 	DE_ASSERT(deIsAlignedPtr(ptr, alignBytes));
    525 	if (!ptr && pool->util)
    526 		pool->util->allocFailCallback(pool->util->userPointer);
    527 	return ptr;
    528 }
    529 
    530 /*--------------------------------------------------------------------*//*!
    531  * \brief Duplicate a piece of memory into a memory pool.
    532  * \param pool	Memory pool to allocate from.
    533  * \param ptr	Piece of memory to duplicate.
    534  * \return Pointer to the copied memory block (or null on failure).
    535  *//*--------------------------------------------------------------------*/
    536 void* deMemPool_memDup (deMemPool* pool, const void* ptr, int numBytes)
    537 {
    538 	void* newPtr = deMemPool_alloc(pool, numBytes);
    539 	if (newPtr)
    540 		memcpy(newPtr, ptr, numBytes);
    541 	return newPtr;
    542 }
    543 
    544 /*--------------------------------------------------------------------*//*!
    545  * \brief Duplicate a string into a memory pool.
    546  * \param pool	Memory pool to allocate from.
    547  * \param str	String to duplicate.
    548  * \return Pointer to the new string (or null on failure).
    549  *//*--------------------------------------------------------------------*/
    550 char* deMemPool_strDup (deMemPool* pool, const char* str)
    551 {
    552 	int		len		= (int)strlen(str);
    553 	char*	newStr	= (char*)deMemPool_alloc(pool, len+1);
    554 	if (newStr)
    555 		memcpy(newStr, str, len+1);
    556 	return newStr;
    557 }
    558 
    559 /*--------------------------------------------------------------------*//*!
    560  * \brief Duplicate a string into a memory pool, with a maximum length.
    561  * \param pool		Memory pool to allocate from.
    562  * \param str		String to duplicate.
    563  * \param maxLength	Maximum number of characters to duplicate.
    564  * \return Pointer to the new string (or null on failure).
    565  *//*--------------------------------------------------------------------*/
    566 char* deMemPool_strnDup (deMemPool* pool, const char* str, int maxLength)
    567 {
    568 	int		len			= deMin32((int)strlen(str), maxLength);
    569 	char*	newStr		= (char*)deMemPool_alloc(pool, len + 1);
    570 	if (newStr)
    571 	{
    572 		memcpy(newStr, str, len);
    573 		newStr[len] = 0;
    574 	}
    575 	return newStr;
    576 }
    577 
    578 #if defined(DE_SUPPORT_POOL_MEMORY_TRACKING)
    579 
    580 int deMemPool_getMaxNumAllocatedBytes (const deMemPool* pool)
    581 {
    582 	DE_ASSERT(pool && !pool->parent); /* must be root */
    583 	return deMax32(pool->maxMemoryAllocated, deMemPool_getNumAllocatedBytes(pool, DE_TRUE));
    584 }
    585 
    586 int deMemPool_getMaxCapacity (const deMemPool* pool)
    587 {
    588 	DE_ASSERT(pool && !pool->parent); /* must be root */
    589 	return deMax32(pool->maxMemoryCapacity, deMemPool_getCapacity(pool, DE_TRUE));
    590 }
    591 
    592 #endif
    593