Verified Commit 02ed1b57 authored by Felix Kopp's avatar Felix Kopp
Browse files

malloc: mask flags for neighbor offset

parent f85006f2
...@@ -120,12 +120,14 @@ static LIST_HEAD(generic_heap); ...@@ -120,12 +120,14 @@ static LIST_HEAD(generic_heap);
static MUTEX(generic_heap_lock); static MUTEX(generic_heap_lock);
static void *generic_heap_start; static void *generic_heap_start;
static void *generic_heap_end; static void *generic_heap_end;
size_t generic_heap_free;
size_t generic_heap_overhead = OVERHEAD;
static LIST_HEAD(atomic_heap); static LIST_HEAD(atomic_heap);
static void *atomic_heap_start; static void *atomic_heap_start;
static void *atomic_heap_end; static void *atomic_heap_end;
size_t atomic_heap_free;
/* forward declaration of utility functions used throughout the file */ size_t atomic_heap_overhead = OVERHEAD;
/** @brief Get the usable block size in bytes, without flags or overhead. */ /** @brief Get the usable block size in bytes, without flags or overhead. */
static size_t blk_get_size(struct memblk *blk); static size_t blk_get_size(struct memblk *blk);
...@@ -162,24 +164,6 @@ static struct memblk *blk_slice(struct list_head *heap, struct memblk *bottom, s ...@@ -162,24 +164,6 @@ static struct memblk *blk_slice(struct list_head *heap, struct memblk *bottom, s
void malloc_init(void *heap, size_t size) void malloc_init(void *heap, size_t size)
{ {
# ifdef DEBUG
if (heap == NULL) {
__breakpoint;
}
if (size == 0) {
__breakpoint;
}
if (size - OVERHEAD - MIN_SIZE < CONFIG_IOMEM_SIZE) {
__breakpoint;
}
if (!list_is_empty(&generic_heap)) {
__breakpoint;
}
if (!list_is_empty(&atomic_heap)) {
__breakpoint;
}
# endif
memset(heap, 0, size); memset(heap, 0, size);
generic_heap_start = heap; generic_heap_start = heap;
...@@ -194,6 +178,7 @@ void malloc_init(void *heap, size_t size) ...@@ -194,6 +178,7 @@ void malloc_init(void *heap, size_t size)
blk_set_border_start(generic_block); blk_set_border_start(generic_block);
blk_set_border_end(generic_block); blk_set_border_end(generic_block);
list_insert(&generic_heap, &generic_block->list); list_insert(&generic_heap, &generic_block->list);
generic_heap_free = blk_get_size(generic_block);
struct memblk *atomic_block = heap + size - CONFIG_IOMEM_SIZE; struct memblk *atomic_block = heap + size - CONFIG_IOMEM_SIZE;
blk_set_size(atomic_block, CONFIG_IOMEM_SIZE - OVERHEAD); blk_set_size(atomic_block, CONFIG_IOMEM_SIZE - OVERHEAD);
...@@ -201,6 +186,7 @@ void malloc_init(void *heap, size_t size) ...@@ -201,6 +186,7 @@ void malloc_init(void *heap, size_t size)
blk_set_border_start(atomic_block); blk_set_border_start(atomic_block);
blk_set_border_end(atomic_block); blk_set_border_end(atomic_block);
list_insert(&atomic_heap, &atomic_block->list); list_insert(&atomic_heap, &atomic_block->list);
atomic_heap_free = blk_get_size(atomic_block);
} }
void *malloc(size_t size) void *malloc(size_t size)
...@@ -208,12 +194,18 @@ void *malloc(size_t size) ...@@ -208,12 +194,18 @@ void *malloc(size_t size)
if (size == 0) if (size == 0)
return NULL; /* as per POSIX */ return NULL; /* as per POSIX */
if (size > generic_heap_free)
return NULL;
/* /*
* Round up towards the next whole allocation unit. GCC is smart enough * Round up towards the next whole allocation unit. GCC is smart enough
* to replace the division/multiplication pair with a bitfield clear * to replace the division/multiplication pair with a bitfield clear
* instruction (MIN_SIZE is always a power of two), so this is okay. * instruction (MIN_SIZE is always a power of two), so this is okay.
*/ */
size = (size / MIN_SIZE) * MIN_SIZE + MIN_SIZE; size_t original_size = size;
size = (size / MIN_SIZE) * MIN_SIZE;
if (size < original_size)
size += MIN_SIZE;
mutex_lock(&generic_heap_lock); mutex_lock(&generic_heap_lock);
...@@ -227,6 +219,7 @@ void *malloc(size_t size) ...@@ -227,6 +219,7 @@ void *malloc(size_t size)
if (blk_get_size(cursor) >= size) { if (blk_get_size(cursor) >= size) {
cursor = blk_slice(&generic_heap, cursor, size); cursor = blk_slice(&generic_heap, cursor, size);
generic_heap_free -= blk_get_size(cursor);
ptr = cursor->data; ptr = cursor->data;
} }
...@@ -240,7 +233,13 @@ void *atomic_malloc(size_t size) ...@@ -240,7 +233,13 @@ void *atomic_malloc(size_t size)
if (size == 0) if (size == 0)
return NULL; return NULL;
size = (size / MIN_SIZE) * MIN_SIZE + MIN_SIZE; if (size > atomic_heap_free)
return NULL;
size_t original_size = size;
size = (size / MIN_SIZE) * MIN_SIZE;
if (size < original_size)
size += MIN_SIZE;
atomic_enter(); atomic_enter();
...@@ -254,6 +253,7 @@ void *atomic_malloc(size_t size) ...@@ -254,6 +253,7 @@ void *atomic_malloc(size_t size)
if (blk_get_size(cursor) >= size) { if (blk_get_size(cursor) >= size) {
cursor = blk_slice(&atomic_heap, cursor, size); cursor = blk_slice(&atomic_heap, cursor, size);
atomic_heap_free -= blk_get_size(cursor);
ptr = cursor->data; ptr = cursor->data;
} }
...@@ -290,6 +290,7 @@ void free(void *ptr) ...@@ -290,6 +290,7 @@ void free(void *ptr)
__breakpoint; __breakpoint;
mutex_lock(&generic_heap_lock); mutex_lock(&generic_heap_lock);
generic_heap_free += blk_get_size(blk);
blk_clear_alloc(blk); blk_clear_alloc(blk);
blk_try_merge(&generic_heap, blk); blk_try_merge(&generic_heap, blk);
mutex_unlock(&generic_heap_lock); mutex_unlock(&generic_heap_lock);
...@@ -298,6 +299,7 @@ void free(void *ptr) ...@@ -298,6 +299,7 @@ void free(void *ptr)
__breakpoint; __breakpoint;
atomic_enter(); atomic_enter();
atomic_heap_free += blk_get_size(blk);
blk_clear_alloc(blk); blk_clear_alloc(blk);
blk_try_merge(&atomic_heap, blk); blk_try_merge(&atomic_heap, blk);
atomic_leave(); atomic_leave();
...@@ -318,7 +320,7 @@ void free(void *ptr) ...@@ -318,7 +320,7 @@ void free(void *ptr)
#define BORDER_FLAG ((size_t)1 << 1) #define BORDER_FLAG ((size_t)1 << 1)
#define SIZE_MSK ( ~(ALLOC_FLAG | BORDER_FLAG) ) #define SIZE_MSK ( ~(ALLOC_FLAG | BORDER_FLAG) )
static inline struct memblk *blk_try_merge(struct list_head *heap, struct memblk *blk) static struct memblk *blk_try_merge(struct list_head *heap, struct memblk *blk)
{ {
struct memblk *neighbor = blk_prev(blk); struct memblk *neighbor = blk_prev(blk);
if (neighbor != NULL && !blk_is_alloc(neighbor)) { if (neighbor != NULL && !blk_is_alloc(neighbor)) {
...@@ -342,7 +344,7 @@ static inline struct memblk *blk_try_merge(struct list_head *heap, struct memblk ...@@ -342,7 +344,7 @@ static inline struct memblk *blk_try_merge(struct list_head *heap, struct memblk
return blk; return blk;
} }
static inline struct memblk *blk_merge(struct list_head *heap, static struct memblk *blk_merge(struct list_head *heap,
struct memblk *bottom, struct memblk *bottom,
struct memblk *top) struct memblk *top)
{ {
...@@ -352,6 +354,14 @@ static inline struct memblk *blk_merge(struct list_head *heap, ...@@ -352,6 +354,14 @@ static inline struct memblk *blk_merge(struct list_head *heap,
blk_set_size(bottom, total_size); blk_set_size(bottom, total_size);
if (heap == &atomic_heap) {
atomic_heap_free += OVERHEAD;
atomic_heap_overhead -= OVERHEAD;
} else {
generic_heap_free += OVERHEAD;
generic_heap_overhead -= OVERHEAD;
}
return bottom; return bottom;
} }
...@@ -365,6 +375,14 @@ static struct memblk *blk_slice(struct list_head *heap, struct memblk *blk, size ...@@ -365,6 +375,14 @@ static struct memblk *blk_slice(struct list_head *heap, struct memblk *blk, size
return blk; /* hand out the entire block */ return blk; /* hand out the entire block */
} }
if (heap == &atomic_heap) {
atomic_heap_overhead += OVERHEAD;
atomic_heap_free -= OVERHEAD;
} else {
generic_heap_overhead += OVERHEAD;
generic_heap_free -= OVERHEAD;
}
size_t slice_words = slice_size / sizeof(blk->size); size_t slice_words = slice_size / sizeof(blk->size);
struct memblk *rest = (void *)&blk->endsz[slice_words + 1]; struct memblk *rest = (void *)&blk->endsz[slice_words + 1];
blk_set_size(rest, rest_size); blk_set_size(rest, rest_size);
...@@ -459,7 +477,7 @@ static inline struct memblk *blk_prev(struct memblk *blk) ...@@ -459,7 +477,7 @@ static inline struct memblk *blk_prev(struct memblk *blk)
{ {
if (blk_is_border_start(blk)) if (blk_is_border_start(blk))
return NULL; return NULL;
return (void *)blk - blk->prevsz[-1] - OVERHEAD; return (void *)blk - (blk->prevsz[-1] & SIZE_MSK) - OVERHEAD;
} }
static inline struct memblk *blk_next(struct memblk *blk) static inline struct memblk *blk_next(struct memblk *blk)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment