Skip to content

Commit

Permalink
Remove mem pool try_alloc (cannot fail now, beyond EOM), bugfix in as…
Browse files Browse the repository at this point in the history
…et for odd combo of NULL and clear'd array
  • Loading branch information
RandyGaul committed Oct 12, 2024
1 parent 1d0bb61 commit 5ca2151
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 125 deletions.
5 changes: 0 additions & 5 deletions docs/allocator/cf_destroy_memory_pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,8 @@ Parameters | Description
--- | ---
pool | The pool to destroy.
## Remarks
Does not clean up any allocations that overflowed to `malloc` backup. See [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) for more details.
## Related Pages
[cf_make_memory_pool](/allocator/cf_make_memory_pool.md)
[cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md)
[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md)
[cf_memory_pool_free](/allocator/cf_memory_pool_free.md)
1 change: 0 additions & 1 deletion docs/allocator/cf_make_memory_pool.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,4 @@ Returns a memory pool pointer.
[cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md)
[cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md)
[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md)
[cf_memory_pool_free](/allocator/cf_memory_pool_free.md)
7 changes: 0 additions & 7 deletions docs/allocator/cf_memory_pool_alloc.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,8 @@ pool | The pool.
Returns an aligned pointer of `size` bytes.
## Remarks
Attempts to allocate from the internal pool. If the pool is empty a call to `malloc` is made as a backup. All
backup allocations are not tracked anywhere, so you must call [cf_memory_pool_free](/allocator/cf_memory_pool_free.md) on each allocation to be
sure they all properly cleaned up.
## Related Pages
[cf_make_memory_pool](/allocator/cf_make_memory_pool.md)
[cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md)
[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md)
[cf_memory_pool_free](/allocator/cf_memory_pool_free.md)
3 changes: 1 addition & 2 deletions docs/allocator/cf_memory_pool_free.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Category: [allocator](/api_reference?id=allocator)
GitHub: [cute_alloc.h](https://github.com/RandyGaul/cute_framework/blob/master/include/cute_alloc.h)
---

Frees an allocation made by [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md) or [cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md).
Frees an allocation made by [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md).

```cpp
void cf_memory_pool_free(CF_MemoryPool* pool, void* element);
Expand All @@ -25,4 +25,3 @@ element | The pointer to deallocate.
[cf_make_memory_pool](/allocator/cf_make_memory_pool.md)
[cf_destroy_memory_pool](/allocator/cf_destroy_memory_pool.md)
[cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md)
[cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md)
36 changes: 0 additions & 36 deletions docs/allocator/cf_memory_pool_try_alloc.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ This is a list of all functions in Cute Framework organized by categories. This
- [cf_make_memory_pool](/allocator/cf_make_memory_pool.md)
- [cf_memory_pool_alloc](/allocator/cf_memory_pool_alloc.md)
- [cf_memory_pool_free](/allocator/cf_memory_pool_free.md)
- [cf_memory_pool_try_alloc](/allocator/cf_memory_pool_try_alloc.md)
- [cf_realloc](/allocator/cf_realloc.md)


Expand Down
27 changes: 5 additions & 22 deletions include/cute_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ typedef struct CF_MemoryPool CF_MemoryPool;
* @param element_count The number of elements in the internal pool.
* @param alignment An alignment boundary, must be a power of two.
* @return Returns a memory pool pointer.
* @related cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_try_alloc cf_memory_pool_free
* @related cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_free
*/
CF_API CF_MemoryPool* CF_CALL cf_make_memory_pool(int element_size, int element_count, int alignment);

Expand All @@ -212,8 +212,7 @@ CF_API CF_MemoryPool* CF_CALL cf_make_memory_pool(int element_size, int element_
* @category allocator
* @brief Destroys a memory pool.
* @param pool The pool to destroy.
* @remarks Does not clean up any allocations that overflowed to `malloc` backup. See `cf_memory_pool_alloc` for more details.
* @related cf_make_memory_pool cf_memory_pool_alloc cf_memory_pool_try_alloc cf_memory_pool_free
* @related cf_make_memory_pool cf_memory_pool_alloc cf_memory_pool_free
*/
CF_API void CF_CALL cf_destroy_memory_pool(CF_MemoryPool* pool);

Expand All @@ -223,32 +222,17 @@ CF_API void CF_CALL cf_destroy_memory_pool(CF_MemoryPool* pool);
* @brief Allocates a chunk of memory from the pool. The allocation size was determined by `element_size` in `cf_make_memory_pool`.
* @param pool The pool.
* @return Returns an aligned pointer of `size` bytes.
* @remarks Attempts to allocate from the internal pool. If the pool is empty a call to `malloc` is made as a backup. All
* backup allocations are not tracked anywhere, so you must call `cf_memory_pool_free` on each allocation to be
* sure they all properly cleaned up.
* @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_try_alloc cf_memory_pool_free
* @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_free
*/
CF_API void* CF_CALL cf_memory_pool_alloc(CF_MemoryPool* pool);

/**
* @function cf_memory_pool_try_alloc
* @category allocator
* @brief Allocates a chunk of memory from the pool. The allocation size was determined by `element_size` in `cf_make_memory_pool`.
* @param pool The pool.
* @return Returns an aligned pointer of `size` bytes.
* @remarks Does not return an allocation if the internal pool is full, and will instead return `NULL` in this case. See
* `cf_memory_pool_alloc` for more details about overflowing the pool to use `malloc` as a backup.
* @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_free
*/
CF_API void* CF_CALL cf_memory_pool_try_alloc(CF_MemoryPool* pool);

/**
* @function cf_memory_pool_free
* @category allocator
* @brief Frees an allocation made by `cf_memory_pool_alloc` or `cf_memory_pool_try_alloc`.
* @brief Frees an allocation made by `cf_memory_pool_alloc`.
* @param pool The pool.
* @param element The pointer to deallocate.
* @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_alloc cf_memory_pool_try_alloc
* @related cf_make_memory_pool cf_destroy_memory_pool cf_memory_pool_alloc
*/
CF_API void CF_CALL cf_memory_pool_free(CF_MemoryPool* pool, void* element);

Expand All @@ -274,7 +258,6 @@ CF_INLINE void arena_reset(CF_Arena* arena) { return cf_arena_reset(arena); }
CF_INLINE CF_MemoryPool* make_memory_pool(int element_size, int element_count, int alignment) { return cf_make_memory_pool(element_size, element_count, alignment); }
CF_INLINE void destroy_memory_pool(CF_MemoryPool* pool) { cf_destroy_memory_pool(pool); }
CF_INLINE void* memory_pool_alloc(CF_MemoryPool* pool) { return cf_memory_pool_alloc(pool); }
CF_INLINE void* memory_pool_try_alloc(CF_MemoryPool* pool) { return cf_memory_pool_try_alloc(pool); }
CF_INLINE void memory_pool_free(CF_MemoryPool* pool, void* element) { return cf_memory_pool_free(pool, element); }

}
Expand Down
104 changes: 54 additions & 50 deletions src/cute_alloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,88 +142,92 @@ void cf_arena_reset(CF_Arena* arena)

//--------------------------------------------------------------------------------------------------

struct CF_MemoryBlock
{
uint8_t* memory;
CF_MemoryBlock* next;
};

struct CF_MemoryPool
{
int unaligned_element_size;
int element_size;
size_t arena_size;
size_t block_size;
int alignment;
uint8_t* arena;
void* free_list;
int overflow_count;
CF_MemoryBlock* blocks;
int element_count_per_block;
};

CF_MemoryPool* cf_make_memory_pool(int element_size, int element_count, int alignment)
{
element_size = element_size > sizeof(void*) ? element_size : sizeof(void*);
int unaligned_element_size = element_size;
element_size = CF_ALIGN_FORWARD(element_size, alignment);
size_t header_size = CF_ALIGN_FORWARD(sizeof(CF_MemoryPool), alignment);
CF_MemoryPool* pool = (CF_MemoryPool*)cf_aligned_alloc(header_size + element_size * element_count, alignment);
size_t block_size = element_size * element_count;

pool->unaligned_element_size = unaligned_element_size;
CF_MemoryPool* pool = (CF_MemoryPool*)cf_aligned_alloc(sizeof(CF_MemoryPool), alignment);
pool->element_size = element_size;
pool->arena_size = (size_t)element_size * element_count;
pool->arena = (uint8_t*)((uintptr_t)pool + header_size);
pool->free_list = pool->arena;
pool->overflow_count = 0;

pool->block_size = block_size;
pool->alignment = alignment;
pool->free_list = NULL;
pool->element_count_per_block = element_count;

// Allocate the first block and initialize the free list.
CF_MemoryBlock* block = (CF_MemoryBlock*)cf_aligned_alloc(sizeof(CF_MemoryBlock), alignment);
block->memory = (uint8_t*)cf_aligned_alloc(block_size, alignment);
block->next = NULL;
pool->blocks = block;
pool->free_list = block->memory;
for (int i = 0; i < element_count - 1; ++i) {
void** element = (void**)(pool->arena + element_size * i);
void* next = (void*)(pool->arena + element_size * (i + 1));
void** element = (void**)(block->memory + element_size * i);
void* next = (void*)(block->memory + element_size * (i + 1));
*element = next;
};

void** last_element = (void**)(pool->arena + element_size * (element_count - 1));
}
void** last_element = (void**)(block->memory + element_size * (element_count - 1));
*last_element = NULL;

return pool;
}

void cf_destroy_memory_pool(CF_MemoryPool* pool)
{
if (pool->overflow_count) {
// Attempted to destroy pool without freeing all overflow allocations.
CF_ASSERT(pool->overflow_count == 0);
CF_MemoryBlock* block = pool->blocks;
while (block) {
CF_MemoryBlock* next = block->next;
cf_aligned_free(block->memory);
cf_aligned_free(block);
block = next;
}
cf_aligned_free(pool);
}

void* cf_memory_pool_alloc(CF_MemoryPool* pool)
{
void *mem = cf_memory_pool_try_alloc(pool);
if (!mem) {
mem = cf_aligned_alloc(pool->unaligned_element_size, pool->alignment);
if (mem) {
pool->overflow_count++;
}
}
return mem;
}

void* cf_memory_pool_try_alloc(CF_MemoryPool* pool)
{
// Try to allocate from the free list first.
if (pool->free_list) {
void *mem = pool->free_list;
pool->free_list = *((void**)pool->free_list);
void* mem = pool->free_list;
pool->free_list = *(void**)pool->free_list;
return mem;
} else {
return NULL;
}

// If no free elements, allocate a new block and initialize its free list.
CF_MemoryBlock* new_block = (CF_MemoryBlock*)cf_aligned_alloc(sizeof(CF_MemoryBlock), pool->alignment);
new_block->memory = (uint8_t*)cf_aligned_alloc(pool->block_size, pool->alignment);
new_block->next = pool->blocks;
pool->blocks = new_block;
pool->free_list = new_block->memory;
for (int i = 0; i < pool->element_count_per_block - 1; ++i) {
void** element = (void**)(new_block->memory + pool->element_size * i);
void* next = (void*)(new_block->memory + pool->element_size * (i + 1));
*element = next;
}
void** last_element = (void**)(new_block->memory + pool->element_size * (pool->element_count_per_block - 1));
*last_element = NULL;

return cf_memory_pool_alloc(pool);
}

void cf_memory_pool_free(CF_MemoryPool* pool, void* element)
{
int difference = (int)((uint8_t*)element - pool->arena);
bool in_bounds = (void*)element >= pool->arena && difference <= (pool->arena_size - pool->element_size);
if (pool->overflow_count && !in_bounds) {
cf_aligned_free(element);
pool->overflow_count--;
} else if (in_bounds) {
*(void**)element = pool->free_list;
pool->free_list = element;
} else {
// Tried to free something that definitely didn't come from this pool.
CF_ASSERT(false);
}
}
*(void**)element = pool->free_list;
pool->free_list = element;
}
3 changes: 2 additions & 1 deletion src/cute_array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ void* cf_aset(const void* a, const void* b, size_t element_size)
a = cf_agrow(a, asize(b), element_size);
}
CF_MEMCPY((void*)a, b, asize(b) * element_size);
alen(a) = asize(b);
if (a) alen(a) = asize(b);
else CF_ASSERT(!asize(b));
return (void*)a;
}

Expand Down

0 comments on commit 5ca2151

Please sign in to comment.