lib/os/heap: some code simplification in sys_heap_aligned_alloc()

It is clearer to apply the alignment in the memory address space
rather than the chunk space.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2020-06-24 01:10:14 -04:00 committed by Andrew Boie
parent 5385d49029
commit 8a6b02b5bf

View file

@ -157,14 +157,19 @@ static void free_chunks(struct z_heap *h, chunkid_t c)
free_list_add(h, c);
}
static chunkid_t mem_to_chunkid(struct z_heap *h, void *p)
{
uint8_t *mem = p, *base = (uint8_t *)chunk_buf(h);
return (mem - chunk_header_bytes(h) - base) / CHUNK_UNIT;
}
void sys_heap_free(struct sys_heap *heap, void *mem)
{
if (mem == NULL) {
return; /* ISO C free() semantics */
}
struct z_heap *h = heap->heap;
chunkid_t c = ((uint8_t *)mem - chunk_header_bytes(h)
- (uint8_t *)chunk_buf(h)) / CHUNK_UNIT;
chunkid_t c = mem_to_chunkid(h, mem);
/*
* This should catch many double-free cases.
@ -251,46 +256,53 @@ void *sys_heap_aligned_alloc(struct sys_heap *heap, size_t align, size_t bytes)
CHECK((align & (align - 1)) == 0);
CHECK(big_heap(h));
if (align <= CHUNK_UNIT) {
return sys_heap_alloc(heap, bytes);
}
if (bytes == 0) {
return NULL;
}
/* Find a free block that is guaranteed to fit */
size_t chunksz = bytes_to_chunksz(h, bytes);
size_t mask = (align / CHUNK_UNIT) - 1;
size_t padsz = MAX(CHUNK_UNIT, chunksz + mask);
chunkid_t c0 = alloc_chunks(h, padsz);
/*
* Find a free block that is guaranteed to fit.
* We over-allocate to account for alignment and then free
* the extra allocations afterwards.
*/
size_t alloc_sz = bytes_to_chunksz(h, bytes);
size_t padded_sz = bytes_to_chunksz(h, bytes + align - 1);
chunkid_t c0 = alloc_chunks(h, padded_sz);
if (c0 == 0) {
return NULL;
}
/* Align within memory, using "chunk index" units. Remember
* the block we're aligning starts in the chunk AFTER the
* header!
*/
size_t c0i = ((size_t) &chunk_buf(h)[c0 + 1]) / CHUNK_UNIT;
size_t ci = ((c0i + mask) & ~mask);
chunkid_t c = c0 + (ci - c0i);
/* Align allocated memory */
void *mem = chunk_mem(h, c0);
mem = (void *) ROUND_UP(mem, align);
CHECK(c >= c0 && c < c0 + padsz);
CHECK((((size_t) chunk_mem(h, c)) & (align - 1)) == 0);
/* Get corresponding chunk */
chunkid_t c = mem_to_chunkid(h, mem);
CHECK(c >= c0 && c < c0 + padded_sz);
/* Split and free unused prefix */
if (c > c0) {
split_chunks(h, c0, c);
set_chunk_used(h, c, true);
free_chunks(h, c0);
/* this can't be merged */
CHECK(chunk_used(h, left_chunk(h, c0)));
free_list_add(h, c0);
}
/* Split and free unused suffix */
if (chunksz < chunk_size(h, c)) {
split_chunks(h, c, c + chunksz);
if (alloc_sz < chunk_size(h, c)) {
split_chunks(h, c, c + alloc_sz);
set_chunk_used(h, c, true);
free_chunks(h, c + alloc_sz);
} else {
set_chunk_used(h, c, true);
free_chunks(h, c + chunksz);
}
return chunk_mem(h, c);
return mem;
}
void sys_heap_init(struct sys_heap *heap, void *mem, size_t bytes)