Skip to content

Commit 5595f66

Browse files
mkometnashif
authored andcommitted
multi_heap: introduce support for realloc()
Add support for realloc (and realloc_aligned) into the multi heap lib, where the buffer sent in will either be reused (maybe shrinked), or enlarged by allocating on any of the matching heaps of the multi heap. Signed-off-by: Meir Komet <[email protected]>
1 parent 0cf8660 commit 5595f66

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

doc/kernel/memory_management/heap.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ application-provided callback is responsible for doing the underlying
127127
allocation from one of the managed heaps, and may use the
128128
configuration parameter in any way it likes to make that decision.
129129

130+
For modifying the size of an allocated buffer (whether shrinking
131+
or enlarging it), you can use the
132+
:c:func:`sys_multi_heap_realloc` and
133+
:c:func:`sys_multi_heap_aligned_realloc` APIs. If the buffer cannot be
134+
enlarged on the heap where it currently resides,
135+
any of the eligible heaps specified by the configuration parameter may be used.
136+
130137
When unused, a multi heap may be freed via
131138
:c:func:`sys_multi_heap_free`. The application does not need to pass
132139
a configuration parameter. Memory allocated from any of the managed

include/zephyr/sys/multi_heap.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,32 @@ const struct sys_multi_heap_rec *sys_multi_heap_get_heap(const struct sys_multi_
168168
*/
169169
void sys_multi_heap_free(struct sys_multi_heap *mheap, void *block);
170170

171+
/** @brief Expand the size of an existing allocation on the multi heap
172+
*
173+
* Returns a pointer to a new memory region with the same contents,
174+
* but a different allocated size. If the new allocation can be
175+
* expanded in place, the pointer returned will be identical.
176+
* Otherwise the data will be copies to a new block and the old one
177+
* will be freed as per sys_heap_free(). If the specified size is
178+
* smaller than the original, the block will be truncated in place and
179+
* the remaining memory returned to the heap. If the allocation of a
180+
* new block fails, then NULL will be returned and the old block will
181+
* not be freed or modified. If a new allocation is needed, the choice
182+
* for the heap used will be bases on the cfg parameter (same as in sys_multi_heap_aligned_alloc).
183+
*
184+
* @param mheap Multi heap pointer
185+
* @param cfg Opaque configuration parameter, as for sys_multi_heap_fn_t
186+
* @param ptr Original pointer returned from a previous allocation
187+
* @param align Alignment in bytes, must be a power of two
188+
* @param bytes Number of bytes requested for the new block
189+
* @return Pointer to memory the caller can now use, or NULL
190+
*/
191+
void *sys_multi_heap_aligned_realloc(struct sys_multi_heap *mheap, void *cfg,
192+
void *ptr, size_t align, size_t bytes);
193+
194+
#define sys_multi_heap_realloc(mheap, cfg, ptr, bytes) \
195+
sys_multi_heap_aligned_realloc(mheap, cfg, ptr, 0, bytes)
196+
171197
/**
172198
* @}
173199
*/

lib/heap/multi_heap.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <zephyr/sys/util.h>
66
#include <zephyr/sys/sys_heap.h>
77
#include <zephyr/sys/multi_heap.h>
8+
#include <string.h>
89

910
void sys_multi_heap_init(struct sys_multi_heap *heap, sys_multi_heap_fn_t choice_fn)
1011
{
@@ -90,3 +91,38 @@ void sys_multi_heap_free(struct sys_multi_heap *mheap, void *block)
9091
sys_heap_free(heap->heap, block);
9192
}
9293
}
94+
95+
void *sys_multi_heap_aligned_realloc(struct sys_multi_heap *mheap, void *cfg,
96+
void *ptr, size_t align, size_t bytes)
97+
{
98+
/* special realloc semantics */
99+
if (ptr == NULL) {
100+
return sys_multi_heap_aligned_alloc(mheap, cfg, align, bytes);
101+
}
102+
if (bytes == 0) {
103+
sys_multi_heap_free(mheap, ptr);
104+
return NULL;
105+
}
106+
107+
const struct sys_multi_heap_rec *rec = sys_multi_heap_get_heap(mheap, ptr);
108+
109+
__ASSERT_NO_MSG(rec);
110+
111+
/* Invoke the realloc function on the same heap, to try to reuse in place */
112+
void *new_ptr = sys_heap_aligned_realloc(rec->heap, ptr, align, bytes);
113+
114+
if (new_ptr != NULL) {
115+
return new_ptr;
116+
}
117+
118+
size_t old_size = sys_heap_usable_size(rec->heap, ptr);
119+
120+
/* Otherwise, allocate a new block and copy the data */
121+
new_ptr = sys_multi_heap_aligned_alloc(mheap, cfg, align, bytes);
122+
if (new_ptr != NULL) {
123+
memcpy(new_ptr, ptr, MIN(old_size, bytes));
124+
sys_multi_heap_free(mheap, ptr);
125+
}
126+
127+
return new_ptr;
128+
}

tests/lib/multi_heap/src/test_mheap_api.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ ZTEST(mheap_api, test_multi_heap)
335335
zassert_true(blocks[i] >= &heap_mem[i][0] &&
336336
blocks[i] < &heap_mem[i+1][0],
337337
"allocation not in correct heap");
338+
339+
void *ptr = sys_multi_heap_realloc(&multi_heap, (void *)(long)i,
340+
blocks[i], MHEAP_BYTES / 2);
341+
342+
zassert_equal(ptr, blocks[i], "realloc moved pointer");
338343
}
339344

340345
/* Make sure all heaps fail to allocate another */
@@ -355,5 +360,25 @@ ZTEST(mheap_api, test_multi_heap)
355360
blocks[i] = sys_multi_heap_alloc(&multi_heap, (void *)(long)i,
356361
MHEAP_BYTES / 2);
357362
zassert_not_null(blocks[i], "final re-allocation failed");
363+
364+
/* Allocating smaller buffer should stay within */
365+
void *ptr = sys_multi_heap_realloc(&multi_heap, (void *)(long)i,
366+
blocks[i], MHEAP_BYTES / 4);
367+
zassert_equal(ptr, blocks[i], "realloc should return same value");
368+
369+
ptr = sys_multi_heap_alloc(&multi_heap, (void *)(long)i,
370+
MHEAP_BYTES / 4);
371+
zassert_between_inclusive((uintptr_t)ptr, (uintptr_t)blocks[i] + MHEAP_BYTES / 4,
372+
(uintptr_t)blocks[i] + MHEAP_BYTES / 2 - 1,
373+
"realloc failed to shrink prev buffer");
358374
}
375+
376+
/* Test realloc special cases */
377+
void *ptr = sys_multi_heap_realloc(&multi_heap, (void *)0L,
378+
blocks[0], /* size = */ 0);
379+
zassert_is_null(ptr);
380+
381+
ptr = sys_multi_heap_realloc(&multi_heap, (void *)0L,
382+
/* ptr = */ NULL, MHEAP_BYTES / 4);
383+
zassert_not_null(ptr);
359384
}

0 commit comments

Comments
 (0)