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