diff --git a/.gitignore b/.gitignore index d3df71c..8decbab 100644 --- a/.gitignore +++ b/.gitignore @@ -127,6 +127,7 @@ /tests/test_cmdline_gen /tests/test_cmdline_gen.c /tests/test_elf +/tests/test_malloc /tests/test_mbr /tests/test_memmap /tests/test_multiboot2_common_packing diff --git a/include/kernaux/malloc.h b/include/kernaux/malloc.h index eea90f7..6933112 100644 --- a/include/kernaux/malloc.h +++ b/include/kernaux/malloc.h @@ -5,10 +5,18 @@ extern "C" { #endif +#include #include +typedef struct KernAux_Malloc_Node { + struct KernAux_Malloc_Node *next; + bool free; + size_t actual_size, user_size; + char *block; +} *KernAux_Malloc_Node; + typedef struct KernAux_Malloc { - int foobar; + KernAux_Malloc_Node head; } *KernAux_Malloc; struct KernAux_Malloc KernAux_Malloc_create(); diff --git a/src/malloc.c b/src/malloc.c index 01fbea3..888fad7 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -12,11 +12,15 @@ #include #include +#include #define ALIGN_MASK(align) ((align) - 1) // align should be a power of 2 #define ALIGN_UP(val, align) (((val) + ALIGN_MASK(align)) & ~ALIGN_MASK(align)) -#define MIN_MALLOC_SIZE (32) // 2**5 +#define PTR_ALIGNMENT (sizeof(void*)) // TODO: align node to this value + +#define ALLOC_HEADER_SIZE (offsetof(struct KernAux_Malloc_Node, block)) +#define MIN_ALLOC_SIZE (ALLOC_HEADER_SIZE + 16) struct KernAux_Malloc KernAux_Malloc_create() { @@ -29,7 +33,7 @@ void KernAux_Malloc_init(const KernAux_Malloc malloc) { KERNAUX_ASSERT(malloc); - (void)malloc; + malloc->head = NULL; } void KernAux_Malloc_add_memory_block( @@ -39,11 +43,17 @@ void KernAux_Malloc_add_memory_block( ) { KERNAUX_ASSERT(malloc); KERNAUX_ASSERT(ptr); - KERNAUX_ASSERT(size); + KERNAUX_ASSERT(size >= 2 * sizeof(struct KernAux_Malloc_Node)); - (void)malloc; - (void)ptr; - (void)size; + KernAux_Malloc_Node new_node = ptr; + new_node->free = true; + new_node->actual_size = size; + new_node->user_size = size - sizeof(struct KernAux_Malloc_Node); + + // TODO: lock + new_node->next = malloc->head; + malloc->head = new_node; + // TODO: unlock } void *KernAux_Malloc_malloc(const KernAux_Malloc malloc, const size_t size) @@ -51,19 +61,49 @@ void *KernAux_Malloc_malloc(const KernAux_Malloc malloc, const size_t size) KERNAUX_ASSERT(malloc); if (size == 0) return NULL; - const size_t actual_size = ALIGN_UP(size, MIN_MALLOC_SIZE); - // Too large, let's not care about the case. - if (actual_size < size) return NULL; + KernAux_Malloc_Node node = NULL; + void *ptr = NULL; - (void)malloc; + // TODO: lock - return NULL; + for ( + KernAux_Malloc_Node item_node = malloc->head; + item_node; + item_node = item_node->next + ) { + if (item_node->free && item_node->user_size >= size) { + node = item_node; + break; + } + } + + if (node) { + // Can we split the block? + if (node->actual_size - size >= MIN_ALLOC_SIZE) { + KernAux_Malloc_Node new_node = + (KernAux_Malloc_Node)(((uintptr_t)&node->block) + size); + new_node->free = true; + new_node->actual_size = node->actual_size - size - ALLOC_HEADER_SIZE; + new_node->user_size = node->user_size - size - ALLOC_HEADER_SIZE; + new_node->next = node->next; + node->next = new_node; + } + + node->free = false; + ptr = &node->block; + } + + // TODO: unlock + + return ptr; } void KernAux_Malloc_free(const KernAux_Malloc malloc, void *const ptr) { KERNAUX_ASSERT(malloc); + // TODO: implement this + (void)malloc; (void)ptr; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 4ebfcf7..ac1b2ac 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -93,6 +93,16 @@ test_elf_LDADD = $(top_builddir)/libkernaux.la test_elf_SOURCES = test_elf.c endif +############### +# test_malloc # +############### + +if WITH_MALLOC +TESTS += test_malloc +test_malloc_LDADD = $(top_builddir)/libkernaux.la +test_malloc_SOURCES = test_malloc.c +endif + ############ # test_mbr # ############ diff --git a/tests/test_malloc.c b/tests/test_malloc.c new file mode 100644 index 0000000..735dcd8 --- /dev/null +++ b/tests/test_malloc.c @@ -0,0 +1,36 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +int main() +{ + char memory_block[1000]; + struct KernAux_Malloc alloc = KernAux_Malloc_create(); + KernAux_Malloc_add_memory_block(&alloc, memory_block, sizeof(memory_block)); + + char *const ptr1 = KernAux_Malloc_malloc(&alloc, 100); + assert(ptr1); + assert(ptr1 > memory_block); + assert(ptr1 < &memory_block[1000]); + + char *const ptr2 = KernAux_Malloc_malloc(&alloc, 100); + assert(ptr2); + assert(ptr2 > ptr1); + assert(ptr2 < &memory_block[1000]); + + char *const ptr3 = KernAux_Malloc_malloc(&alloc, 100); + assert(ptr3); + assert(ptr3 > ptr2); + assert(ptr3 < &memory_block[1000]); + + char *const ptr4 = KernAux_Malloc_malloc(&alloc, 100); + assert(ptr4); + assert(ptr4 > ptr3); + assert(ptr4 < &memory_block[1000]); + + return 0; +}