mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Example of setting up malloc heap on extram
This commit is contained in:
parent
7fae8c129f
commit
f27ed6213c
5 changed files with 369 additions and 0 deletions
152
apps/heap/malloc_freelist.c
Normal file
152
apps/heap/malloc_freelist.c
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
//#include <stdint.h>
|
||||
#include "uvm32_target.h"
|
||||
#include "linkedlist.h"
|
||||
|
||||
#pragma mark - Definitions -
|
||||
|
||||
/**
|
||||
* Simple macro for making sure memory addresses are aligned
|
||||
* to the nearest power of two
|
||||
*/
|
||||
#ifndef align_up
|
||||
#define align_up(num, align) (((num) + ((align)-1)) & ~((align)-1))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is the container for our free-list.
|
||||
* Node the usage of the linked list here: the library uses offsetof
|
||||
* and container_of to manage the list and get back to the parent struct.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ll_t node;
|
||||
size_t size;
|
||||
char* block;
|
||||
} alloc_node_t;
|
||||
|
||||
/**
|
||||
* We vend a memory address to the user. This lets us translate back and forth
|
||||
* between the vended pointer and the container we use for managing the data.
|
||||
*/
|
||||
#define ALLOC_HEADER_SZ offsetof(alloc_node_t, block)
|
||||
|
||||
// We are enforcing a minimum allocation size of 32B.
|
||||
#define MIN_ALLOC_SZ ALLOC_HEADER_SZ + 32
|
||||
|
||||
#pragma mark - Prototypes -
|
||||
|
||||
static void defrag_free_list(void);
|
||||
|
||||
#pragma mark - Declarations -
|
||||
|
||||
// This macro simply declares and initializes our linked list
|
||||
static LIST_INIT(free_list);
|
||||
|
||||
#pragma mark - Private Functions -
|
||||
|
||||
/**
|
||||
* When we free, we can take our node and check to see if any memory blocks
|
||||
* can be combined into larger blocks. This will help us fight against
|
||||
* memory fragmentation in a simple way.
|
||||
*/
|
||||
void defrag_free_list(void)
|
||||
{
|
||||
alloc_node_t *block, *last_block = NULL, *t;
|
||||
|
||||
list_for_each_entry_safe(block, t, &free_list, node)
|
||||
{
|
||||
if(last_block)
|
||||
{
|
||||
if((((uintptr_t)&last_block->block) + last_block->size) == (uintptr_t)block)
|
||||
{
|
||||
last_block->size += ALLOC_HEADER_SZ + block->size;
|
||||
list_del(&block->node);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
last_block = block;
|
||||
}
|
||||
}
|
||||
#pragma mark - APIs -
|
||||
|
||||
void* fl_malloc(size_t size)
|
||||
{
|
||||
void* ptr = NULL;
|
||||
alloc_node_t* blk = NULL;
|
||||
|
||||
if(size > 0)
|
||||
{
|
||||
// Align the pointer
|
||||
size = align_up(size, sizeof(void*));
|
||||
|
||||
// try to find a big enough block to alloc
|
||||
list_for_each_entry(blk, &free_list, node)
|
||||
{
|
||||
if(blk->size >= size)
|
||||
{
|
||||
ptr = &blk->block;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we found something
|
||||
if(ptr)
|
||||
{
|
||||
// Can we split the block?
|
||||
if((blk->size - size) >= MIN_ALLOC_SZ)
|
||||
{
|
||||
alloc_node_t* new_blk;
|
||||
new_blk = (alloc_node_t*)((uintptr_t)(&blk->block) + size);
|
||||
new_blk->size = blk->size - size - ALLOC_HEADER_SZ;
|
||||
blk->size = size;
|
||||
list_add_(&new_blk->node, &blk->node, blk->node.next);
|
||||
}
|
||||
|
||||
list_del(&blk->node);
|
||||
}
|
||||
|
||||
} // else NULL
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void fl_free(void* ptr)
|
||||
{
|
||||
alloc_node_t *blk, *free_blk;
|
||||
|
||||
// Don't free a NULL pointer..
|
||||
if(ptr)
|
||||
{
|
||||
// we take the pointer and use container_of to get the corresponding alloc block
|
||||
blk = container_of(ptr, alloc_node_t, block);
|
||||
|
||||
// Let's put it back in the proper spot
|
||||
list_for_each_entry(free_blk, &free_list, node)
|
||||
{
|
||||
if(free_blk > blk)
|
||||
{
|
||||
list_add_(&blk->node, free_blk->node.prev, &free_blk->node);
|
||||
goto blockadded;
|
||||
}
|
||||
}
|
||||
list_add_tail(&blk->node, &free_list);
|
||||
|
||||
blockadded:
|
||||
// Let's see if we can combine any memory
|
||||
defrag_free_list();
|
||||
}
|
||||
}
|
||||
|
||||
void malloc_addblock(void* addr, size_t size)
|
||||
{
|
||||
alloc_node_t* blk;
|
||||
|
||||
// let's align the start address of our block to the next pointer aligned number
|
||||
blk = (void*)align_up((uintptr_t)addr, sizeof(void*));
|
||||
|
||||
// calculate actual size - remove our alignment and our header space from the availability
|
||||
blk->size = (uintptr_t)addr + size - (uintptr_t)blk - ALLOC_HEADER_SZ;
|
||||
|
||||
// and now our giant block of memory is added to the list!
|
||||
list_add(&blk->node, &free_list);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue