Skip to content

Commit

Permalink
realloc(): move mempool internal knowledge out of generic lib code
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
Nicolas Pitre authored and andrewboie committed Sep 30, 2019
1 parent 8940c25 commit 2129937
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 20 deletions.
13 changes: 13 additions & 0 deletions include/sys/mempool.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
25 changes: 5 additions & 20 deletions lib/libc/minimal/source/stdlib/malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
}

Expand All @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions lib/os/mempool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 2129937

Please sign in to comment.