malloc: fix my shit code so it's less shitty

The allocator works now.
At least when i compile it for amd64.
I haven't actually flashed it yet tho lmao.
This commit is contained in:
anna 2021-08-09 04:03:54 +02:00
parent 83ee9603e7
commit 8e9678577e
Signed by: fef
GPG key ID: EC22E476DC2D3D84

View file

@ -227,7 +227,6 @@ 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);
blk_set_alloc(cursor);
ptr = cursor->data; ptr = cursor->data;
} }
@ -255,7 +254,6 @@ 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);
blk_set_alloc(cursor);
ptr = cursor->data; ptr = cursor->data;
} }
@ -282,34 +280,30 @@ void *calloc(size_t nmemb, size_t size)
void free(void *ptr) void free(void *ptr)
{ {
struct memblk *blk = ptr - offsetof(struct memblk, data);
struct list_head *heap;
if (ptr == NULL) if (ptr == NULL)
return; /* as per POSIX.1-2008 */ return; /* as per POSIX.1-2008 */
struct memblk *blk = ptr - offsetof(struct memblk, data);
if (ptr >= generic_heap_start && ptr <= generic_heap_end) { if (ptr >= generic_heap_start && ptr <= generic_heap_end) {
heap = &generic_heap; if (!blk_is_alloc(blk))
__breakpoint;
mutex_lock(&generic_heap_lock); mutex_lock(&generic_heap_lock);
blk_clear_alloc(blk);
blk_try_merge(&generic_heap, blk);
mutex_unlock(&generic_heap_lock);
} else if (ptr >= atomic_heap_start && ptr <= atomic_heap_end) { } else if (ptr >= atomic_heap_start && ptr <= atomic_heap_end) {
heap = &atomic_heap; if (!blk_is_alloc(blk))
__breakpoint;
atomic_enter(); atomic_enter();
blk_clear_alloc(blk);
blk_try_merge(&atomic_heap, blk);
atomic_leave();
} else { } else {
__breakpoint; __breakpoint;
return;
} }
if (!blk_is_alloc(blk)) {
__breakpoint; /* probably double free */
}
blk_clear_alloc(blk);
blk_try_merge(heap, blk);
if (heap == &generic_heap)
mutex_unlock(&generic_heap_lock);
else
atomic_leave();
} }
/* ========================================================================== */ /* ========================================================================== */
@ -326,13 +320,24 @@ void free(void *ptr)
static inline struct memblk *blk_try_merge(struct list_head *heap, struct memblk *blk) static inline struct memblk *blk_try_merge(struct list_head *heap, struct memblk *blk)
{ {
struct memblk *neigh = blk_prev(blk); struct memblk *neighbor = blk_prev(blk);
if (neigh != NULL) if (neighbor != NULL && !blk_is_alloc(neighbor)) {
blk = blk_merge(heap, neigh, blk); list_delete(&neighbor->list);
blk = blk_merge(heap, neighbor, blk);
}
neigh = blk_next(blk); neighbor = blk_next(blk);
if (neigh != NULL) if (neighbor != NULL && !blk_is_alloc(neighbor)) {
blk = blk_merge(heap, blk, neigh); list_delete(&neighbor->list);
blk = blk_merge(heap, blk, neighbor);
}
struct memblk *cursor;
list_for_each_entry(heap, cursor, list) {
if (blk_get_size(cursor) >= blk_get_size(blk))
break;
}
list_insert_before(&cursor->list, &blk->list);
return blk; return blk;
} }
@ -343,68 +348,62 @@ static inline struct memblk *blk_merge(struct list_head *heap,
{ {
size_t bottom_size = blk_get_size(bottom); size_t bottom_size = blk_get_size(bottom);
size_t top_size = blk_get_size(top); size_t top_size = blk_get_size(top);
size_t total_size = bottom_size + top_size; size_t total_size = bottom_size + top_size + OVERHEAD;
list_delete(&top->list);
list_delete(&bottom->list);
blk_set_size(bottom, total_size); blk_set_size(bottom, total_size);
struct memblk *cursor;
list_for_each_entry(heap, cursor, list) {
if (blk_get_size(cursor) <= bottom->size)
break;
}
list_insert_before(&cursor->list, &bottom->list);
return bottom; return bottom;
} }
static inline struct memblk *blk_slice(struct list_head *heap, static struct memblk *blk_slice(struct list_head *heap, struct memblk *blk, size_t slice_size)
struct memblk *bottom,
size_t bottom_size)
{ {
list_delete(&bottom->list); list_delete(&blk->list);
size_t top_size = blk_get_size(bottom) - bottom_size - OVERHEAD; assert((slice_size & SIZE_MSK) == slice_size);
if (top_size < MIN_SIZE) assert(slice_size > 0);
return bottom; /* hand out the entire block */
size_t bottom_words = bottom_size / sizeof(bottom->size); size_t rest_size = blk_get_size(blk) - slice_size - OVERHEAD;
struct memblk *top = (void *)&bottom->endsz[bottom_words + 1]; if (rest_size < MIN_SIZE) {
blk_set_size(top, top_size); blk_set_alloc(blk);
blk_clear_alloc(top); return blk; /* hand out the entire block */
blk_clear_border_start(top); }
blk_set_size(bottom, bottom_size); size_t slice_words = slice_size / sizeof(blk->size);
blk_clear_border_end(bottom); struct memblk *rest = (void *)&blk->endsz[slice_words + 1];
blk_set_size(rest, rest_size);
blk_clear_alloc(rest);
blk_clear_border_start(rest);
blk_set_size(blk, slice_size);
blk_set_alloc(blk);
blk_clear_border_end(blk);
struct memblk *cursor; struct memblk *cursor;
list_for_each_entry(heap, cursor, list) { list_for_each_entry(heap, cursor, list) {
if (blk_get_size(cursor) <= top_size) if (blk_get_size(cursor) <= rest_size)
break; break;
} }
list_insert_before(&cursor->list, &top->list); list_insert_before(&cursor->list, &rest->list);
return bottom; return blk;
} }
static inline size_t blk_get_size(struct memblk *blk) static inline size_t blk_get_size(struct memblk *blk)
{ {
return (blk->size & SIZE_MSK) - OVERHEAD; return blk->size & SIZE_MSK;
} }
static inline void blk_set_size(struct memblk *blk, size_t size) static void blk_set_size(struct memblk *blk, size_t size)
{ {
size &= SIZE_MSK; assert((size & SIZE_MSK) == size);
size += OVERHEAD;
/* sizeof(size_t) is a power of 2 so this division will become a bitshift */ /* don't affect flags */
size_t words = size / sizeof(blk->size);
blk->size &= SIZE_MSK; blk->size &= ~SIZE_MSK;
blk->size |= size; blk->size |= size;
blk->endsz[words] &= SIZE_MSK; size_t words = size / sizeof(blk->size);
blk->endsz[words] &= ~SIZE_MSK;
blk->endsz[words] |= size; blk->endsz[words] |= size;
} }
@ -466,7 +465,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]; return (void *)blk - blk->prevsz[-1] - OVERHEAD;
} }
static inline struct memblk *blk_next(struct memblk *blk) static inline struct memblk *blk_next(struct memblk *blk)
@ -475,7 +474,7 @@ static inline struct memblk *blk_next(struct memblk *blk)
return NULL; return NULL;
size_t words = blk->size / sizeof(blk->size); size_t words = blk->size / sizeof(blk->size);
return (void *)blk->endsz[words + 1]; return (void *)&blk->endsz[words + 1];
} }
/* /*