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
35enum
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
42typedef 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 *//*--------------------------------------------------------------------*/
50struct MemPage_s
51{
52	int			capacity;
53	int			bytesAllocated;
54
55	MemPage*	nextPage;
56};
57
58#if defined(DE_SUPPORT_DEBUG_POOLS)
59typedef struct DebugAlloc_s DebugAlloc;
60
61struct 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 *//*--------------------------------------------------------------------*/
86struct 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 *//*--------------------------------------------------------------------*/
121static 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 *//*--------------------------------------------------------------------*/
136static 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 *//*--------------------------------------------------------------------*/
153static 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 *//*--------------------------------------------------------------------*/
169static 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 *//*--------------------------------------------------------------------*/
241deMemPool* 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 *//*--------------------------------------------------------------------*/
281deMemPool* 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 *//*--------------------------------------------------------------------*/
298void 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 *//*--------------------------------------------------------------------*/
378int 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 *//*--------------------------------------------------------------------*/
390int 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
408int 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
426DE_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 *//*--------------------------------------------------------------------*/
499void* 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 *//*--------------------------------------------------------------------*/
517void* 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 *//*--------------------------------------------------------------------*/
536void* 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 *//*--------------------------------------------------------------------*/
550char* 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 *//*--------------------------------------------------------------------*/
566char* 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
580int 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
586int 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