Refactor and make the allocator work
This commit is contained in:
parent
cd833dbbdf
commit
fc75cb2014
1 changed files with 48 additions and 37 deletions
85
lib/malloc.c
85
lib/malloc.c
|
@ -89,10 +89,38 @@ static void memblk_set_size(struct memblk *block, size_t size)
|
|||
block->size = size;
|
||||
void *endptr = block;
|
||||
endptr += MEMBLK_HDR_SIZE_LENGTH;
|
||||
endptr += ((size >> 1) << 1); /* discard the allocated bit */
|
||||
endptr += ((size >> 1u) << 1u); /* discard the allocated bit */
|
||||
*(size_t *)(endptr) = size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a single free memory block up into two individual blocks such that the block
|
||||
* passed to this function will contain `size` bytes and the newly-created block has
|
||||
* the rest minus overhead. The new block is inserted into the list of free blocks;
|
||||
* however, the original block will *not* be re-sorted.
|
||||
*
|
||||
* @param blk The block to split up.
|
||||
* @param size The new (at least by `MEMBLK_OFFSET + n` bytes smaller) size of the block.
|
||||
* @return The newly created block.
|
||||
*/
|
||||
static struct memblk *memblk_split(struct memblk *blk, size_t size)
|
||||
{
|
||||
struct memblk *cursor;
|
||||
struct memblk *newblk = (void *)blk + MEMBLK_OVERHEAD + ((size >> 1u) << 1u);
|
||||
|
||||
memblk_set_size(newblk, blk->size - MEMBLK_OVERHEAD - ((size >> 1u) << 1u));
|
||||
memblk_set_size(blk, size);
|
||||
|
||||
list_for_each_entry_reverse(&blk->list, cursor, list) {
|
||||
if (cursor->size >= newblk->size || &cursor->list == &memblk_free_list) {
|
||||
list_insert(&cursor->list, &newblk->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return newblk;
|
||||
}
|
||||
|
||||
void malloc_init(void *heap, size_t size)
|
||||
{
|
||||
struct memblk *blk = heap;
|
||||
|
@ -103,21 +131,22 @@ void malloc_init(void *heap, size_t size)
|
|||
* dispatching/handling routines, we should do that here.
|
||||
*/
|
||||
if (list_is_empty(&memblk_free_list)) {
|
||||
memblk_set_size(blk, size);
|
||||
memblk_set_size(blk, size - MEMBLK_OVERHEAD);
|
||||
list_insert(&memblk_free_list, &blk->list);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((malloc))
|
||||
void *malloc(size_t size)
|
||||
{
|
||||
struct memblk *blk, *newblk, *cursor;
|
||||
struct memblk *blk;
|
||||
size_t remaining_blksz;
|
||||
|
||||
if (size == 0)
|
||||
return NULL; /* as per POSIX.1-2008 */
|
||||
|
||||
/* round up to the next multiple of `MIN_BLKSZ` */
|
||||
size = ((size) / MIN_BLKSZ) * MIN_BLKSZ;
|
||||
size = (size / MIN_BLKSZ) * MIN_BLKSZ;
|
||||
size += MIN_BLKSZ;
|
||||
|
||||
list_for_each_entry(&memblk_free_list, blk, list) {
|
||||
|
@ -126,45 +155,28 @@ void *malloc(size_t size)
|
|||
break;
|
||||
}
|
||||
if (blk->size < size)
|
||||
return NULL; /* ENOMEM */
|
||||
return NULL; /* TODO: set errno to ENOMEM once we have it */
|
||||
|
||||
/*
|
||||
* If we've made it to here, we have found a sufficiently big block,
|
||||
* meaning we can't possibly fail anymore. Since that block is likely
|
||||
* larger than the requested size, we are going to check if it is
|
||||
* possible to create a new, smaller block right at the end of the
|
||||
* allocated area.
|
||||
* allocated area. If it isn't, we just hand out the entire block.
|
||||
*/
|
||||
remaining_blksz = blk->size - size;
|
||||
if (remaining_blksz >= MIN_BLKSZ + MEMBLK_OVERHEAD) {
|
||||
/* resize the allocated block to fit the requested length exactly */
|
||||
memblk_set_size(blk, size | 0x1 /* allocated bit */);
|
||||
if (remaining_blksz >= MIN_BLKSZ + MEMBLK_OVERHEAD)
|
||||
memblk_split(blk, size | 0x1u /* allocated bit */);
|
||||
else
|
||||
memblk_set_size(blk, blk->size | 0x1u /* allocated bit */);
|
||||
|
||||
/* create a new smaller block ... */
|
||||
newblk = (void *)blk + blk->size + MEMBLK_OVERHEAD;
|
||||
memblk_set_size(newblk, remaining_blksz);
|
||||
|
||||
/* ... and insert it into the list */
|
||||
list_for_each_entry_reverse(&blk->list, cursor, list) {
|
||||
if (cursor->size < remaining_blksz || &cursor->list == &memblk_free_list) {
|
||||
list_insert(&cursor->list, &newblk->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_delete(&blk->list);
|
||||
} else {
|
||||
/* hand out the entire block */
|
||||
memblk_set_size(blk, blk->size | 0x1 /* allocated bit */);
|
||||
list_delete(&blk->list);
|
||||
}
|
||||
memblk_set_size(blk, size | 0x1 /* allocated bit */);
|
||||
list_delete(&blk->list);
|
||||
|
||||
/* Keep the size field intact */
|
||||
return ((void *)blk) + MEMBLK_HDR_SIZE_LENGTH;
|
||||
}
|
||||
|
||||
__attribute__((malloc))
|
||||
void *calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr = malloc(nmemb * size);
|
||||
|
@ -178,7 +190,7 @@ void *calloc(size_t nmemb, size_t size)
|
|||
/** Merge two neighboring free blocks to one big block */
|
||||
static void memblk_merge(struct memblk *lblk, struct memblk *hblk)
|
||||
{
|
||||
size_t *endsz = (void *)hblk + hblk->size + MEMBLK_OVERHEAD;
|
||||
size_t *endsz = (void *)hblk + hblk->size + MEMBLK_HDR_SIZE_LENGTH;
|
||||
lblk->size = lblk->size + hblk->size + MEMBLK_OVERHEAD;
|
||||
*endsz = lblk->size;
|
||||
}
|
||||
|
@ -192,22 +204,22 @@ void free(void *ptr)
|
|||
if (ptr == NULL)
|
||||
return; /* as per POSIX.1-2008 */
|
||||
|
||||
if ((blk->size & 0x1) == 0)
|
||||
if ((blk->size & 0x1u) == 0)
|
||||
return; /* TODO: Raise exception on double-free */
|
||||
|
||||
memblk_set_size(blk, (blk->size >> 1) << 1 /* clear allocated bit */);
|
||||
memblk_set_size(blk, (blk->size >> 1u) << 1u /* clear allocated bit */);
|
||||
|
||||
/* check if our higher/right neighbor is allocated and merge if it is not */
|
||||
neighsz = (void *)blk + MEMBLK_OVERHEAD + blk->size;
|
||||
if ((*neighsz & 0x1) == 0) {
|
||||
tmp = (struct memblk *)neighsz;
|
||||
if ((*neighsz & 0x1u) == 0) {
|
||||
tmp = container_of(neighsz, struct memblk, size);
|
||||
memblk_merge(blk, tmp);
|
||||
list_delete(&tmp->list);
|
||||
}
|
||||
|
||||
/* same thing for the lower/left block */
|
||||
neighsz = (void *)blk - MEMBLK_HDR_SIZE_LENGTH;
|
||||
if ((*neighsz & 0x1) == 0) {
|
||||
if ((*neighsz & 0x1u) == 0) {
|
||||
tmp = (void *)neighsz - *neighsz - MEMBLK_HDR_SIZE_LENGTH;
|
||||
memblk_merge(tmp, blk);
|
||||
list_delete(&tmp->list);
|
||||
|
@ -215,11 +227,10 @@ void free(void *ptr)
|
|||
}
|
||||
|
||||
list_for_each_entry(&memblk_free_list, tmp, list) {
|
||||
if (tmp->size <= blk->size) {
|
||||
list_insert_before(&tmp->list, &blk->list);
|
||||
if (tmp->size >= blk->size)
|
||||
break;
|
||||
}
|
||||
}
|
||||
list_insert_before(&tmp->list, &blk->list);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue