realloc(): move mempool internal knowledge out of generic lib code

The realloc function was a bit too intimate with the mempool accounting.
Abstract that knowledge away and move it where it belongs.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2019-09-26 17:24:50 -04:00 committed by Andrew Boie
parent 8940c25145
commit 2129937d3d
3 changed files with 45 additions and 20 deletions

View file

@ -99,4 +99,17 @@ void *sys_mem_pool_alloc(struct sys_mem_pool *p, size_t size);
*/
void sys_mem_pool_free(void *ptr);
/**
* @brief Try to perform in-place expansion of memory allocated from a pool
*
* Return 0 if memory previously allocated by sys_mem_pool_alloc()
* can accommodate a new size, otherwise return the size of data that
* needs to be copied over to new memory.
*
* @param ptr Pointer to previously allocated memory
* @param new_size New size requested for the memory block
* @return A 0 if OK, or size of data to copy elsewhere
*/
size_t sys_mem_pool_try_expand_inplace(void *ptr, size_t new_size);
#endif

View file

@ -87,10 +87,8 @@ void *calloc(size_t nmemb, size_t size)
void *realloc(void *ptr, size_t requested_size)
{
struct sys_mem_pool_block *blk;
size_t struct_blk_size = WB_UP(sizeof(struct sys_mem_pool_block));
size_t block_size, total_requested_size;
void *new_ptr;
size_t copy_size;
if (ptr == NULL) {
return malloc(requested_size);
@ -101,22 +99,9 @@ void *realloc(void *ptr, size_t requested_size)
return NULL;
}
/* Stored right before the pointer passed to the user */
blk = (struct sys_mem_pool_block *)((char *)ptr - struct_blk_size);
/* Determine size of previously allocated block by its level.
* Most likely a bit larger than the original allocation
*/
block_size = blk->pool->base.max_sz;
for (int i = 1; i <= blk->level; i++) {
block_size = WB_DN(block_size / 4);
}
/* We really need this much memory */
total_requested_size = requested_size + struct_blk_size;
if (block_size >= total_requested_size) {
/* Existing block large enough, nothing to do */
copy_size = sys_mem_pool_try_expand_inplace(ptr, requested_size);
if (copy_size == 0) {
/* Existing block large enough, nothing else to do */
return ptr;
}
@ -125,7 +110,7 @@ void *realloc(void *ptr, size_t requested_size)
return NULL;
}
memcpy(new_ptr, ptr, block_size - struct_blk_size);
memcpy(new_ptr, ptr, copy_size);
free(ptr);
return new_ptr;

View file

@ -354,3 +354,30 @@ void sys_mem_pool_free(void *ptr)
sys_mutex_unlock(&p->mutex);
}
size_t sys_mem_pool_try_expand_inplace(void *ptr, size_t requested_size)
{
struct sys_mem_pool_block *blk;
size_t struct_blk_size = WB_UP(sizeof(struct sys_mem_pool_block));
size_t block_size, total_requested_size;
ptr = (char *)ptr - struct_blk_size;
blk = (struct sys_mem_pool_block *)ptr;
/*
* Determine size of previously allocated block by its level.
* Most likely a bit larger than the original allocation
*/
block_size = blk->pool->base.max_sz;
for (int i = 1; i <= blk->level; i++) {
block_size = WB_DN(block_size / 4);
}
/* We really need this much memory */
total_requested_size = requested_size + struct_blk_size;
if (block_size >= total_requested_size) {
/* size adjustment can occur in-place */
return 0;
}
return block_size - struct_blk_size;
}