From 2129937d3da2a2c4ddc6a6a542388400c19ba1c6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 26 Sep 2019 17:24:50 -0400 Subject: [PATCH] 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 --- include/sys/mempool.h | 13 ++++++++++++ lib/libc/minimal/source/stdlib/malloc.c | 25 +++++------------------ lib/os/mempool.c | 27 +++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/include/sys/mempool.h b/include/sys/mempool.h index a367f6e8c4b..ff0df6ae224 100644 --- a/include/sys/mempool.h +++ b/include/sys/mempool.h @@ -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 diff --git a/lib/libc/minimal/source/stdlib/malloc.c b/lib/libc/minimal/source/stdlib/malloc.c index cf7fd840eb8..7d040ac399c 100644 --- a/lib/libc/minimal/source/stdlib/malloc.c +++ b/lib/libc/minimal/source/stdlib/malloc.c @@ -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; diff --git a/lib/os/mempool.c b/lib/os/mempool.c index de81468b18a..7061eecd3a7 100644 --- a/lib/os/mempool.c +++ b/lib/os/mempool.c @@ -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; +}