diff --git a/include/Makefile.am b/include/Makefile.am index 9d6bc93..3e004a9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,2 +1,2 @@ nobase_include_HEADERS = libmalloc/bitmap_alloc.h libmalloc/buddy_alloc.h \ - libmalloc/memmap.h libmalloc/common.h \ No newline at end of file + libmalloc/list_alloc.h libmalloc/memmap.h libmalloc/common.h \ No newline at end of file diff --git a/include/libmalloc/list_alloc.h b/include/libmalloc/list_alloc.h new file mode 100644 index 0000000..1b7bb08 --- /dev/null +++ b/include/libmalloc/list_alloc.h @@ -0,0 +1,27 @@ +#ifndef _LIBMALLOC_LISTALLOC_H +#define _LIBMALLOC_LISTALLOC_H + +#include "memmap.h" +#include "common.h" + +typedef struct list_block_t +{ + unsigned long free; + unsigned long size; + struct list_block_t *prev; + struct list_block_t *next; +} list_block_t; + +typedef struct list_alloc_descriptor_t +{ + list_block_t head; + list_block_t *current_block; +} list_alloc_descriptor_t; + +void *list_alloc_reserve(list_alloc_descriptor_t *heap, unsigned long size); + +void list_alloc_free(list_alloc_descriptor_t *heap, void *p); + +int list_alloc_init(list_alloc_descriptor_t *heap, memory_map_t *map); + +#endif \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 43ed361..bea103e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ lib_LIBRARIES = libmalloc.a -libmalloc_a_SOURCES = buddy_alloc.c bitmap_alloc.c memmap.c +libmalloc_a_SOURCES = buddy_alloc.c bitmap_alloc.c list_alloc.c memmap.c libmalloc_a_CFLAGS = -I$(prefix)/include \ No newline at end of file diff --git a/src/list_alloc.c b/src/list_alloc.c new file mode 100644 index 0000000..84e6bd4 --- /dev/null +++ b/src/list_alloc.c @@ -0,0 +1,134 @@ +#include "libmalloc/list_alloc.h" +#include +#include + +#define MIN_BLOCK_SIZE (4 * sizeof(list_block_t)) + +static list_block_t *block_end_ptr(list_block_t *p) +{ + return (list_block_t*)((void*)p + p->size - sizeof(list_block_t)); +} + +static list_block_t *block_start_ptr(list_block_t *p) +{ + return (list_block_t*)((void*)p - p->size + sizeof(list_block_t)); +} + +static void set_block_tag(list_block_t *p, unsigned long free) +{ + p->free = free; + block_end_ptr(p)->free = free; +} + +static void set_block_size(list_block_t *p, unsigned long size) +{ + p->size = size; + block_end_ptr(p)->size = size; +} + +static void set_block_next(list_block_t *p, list_block_t *next) +{ + p->next = next; + block_end_ptr(p)->next = next; +} + +static void set_block_prev(list_block_t *p, list_block_t *prev) +{ + p->prev = prev; + block_end_ptr(p)->prev = prev; +} + +static void set_block(list_block_t *p, unsigned long tag, unsigned long size, + list_block_t *next, list_block_t *prev) +{ + set_block_size(p, size); + set_block_tag(p, tag); + set_block_next(p, next); + set_block_prev(p, prev); +} + +void *list_alloc_reserve(list_alloc_descriptor_t *heap, unsigned long size) +{ + size += sizeof(unsigned long) - 1; + size -= size % sizeof(unsigned long); + list_block_t *p = heap->current_block; + do + { + if(p->size >= (size + 2 * sizeof(list_block_t) + MIN_BLOCK_SIZE)) + { + printf("Reserving partial block.\n"); + unsigned long new_size = p->size - size - (2 * sizeof(list_block_t)); + list_block_t *new_block = (void*)p + new_size; + set_block(new_block, 0, size + 2 * sizeof(list_block_t), 0, 0); + set_block_tag(p, 1); + set_block_size(p, new_size); + heap->current_block = p; + return (void*)new_block + sizeof(list_block_t); + } + else if(p->size >= (size + 2 * sizeof(list_block_t))) + { + printf("Reserving whole block.\n"); + set_block_next(p->prev, p->next); + set_block_prev(p->next, p->prev); + heap->current_block = p->next; + set_block(p, 0, p->size, 0, 0); + return (void*)p + sizeof(list_block_t); + } + p = p->next; + } while(p != heap->current_block); + return NOMEM; +} + +void list_alloc_free(list_alloc_descriptor_t *heap, void *p) +{ + list_block_t *block = (list_block_t*)(p - sizeof(list_block_t)); + + list_block_t *lhs = block_start_ptr(block - 1); + if(lhs->free == 1) + { + printf("Merging left.\n"); + set_block_next(lhs->prev, lhs->next); + set_block_prev(lhs->next, lhs->prev); + unsigned long new_size = block->size + lhs->size; + block = (void*)block - lhs->size; + block->size = new_size; + } + + list_block_t *rhs = (block_end_ptr(block) + 1); + if(rhs->free == 1) + { + printf("Merging right.\n"); + set_block_next(rhs->prev, rhs->next); + set_block_prev(rhs->next, rhs->prev); + block->size += rhs->size; + } + + set_block(block, 1, block->size, &heap->head, heap->head.prev); + set_block_next(heap->head.prev, block); + set_block_prev(&heap->head, block); + heap->current_block = block; +} + +int list_alloc_init(list_alloc_descriptor_t *heap, memory_map_t *map) +{ + heap->head.free = 0; + heap->head.size = sizeof(heap->head); + heap->head.prev = &heap->head; + heap->head.next = &heap->head; + heap->current_block = &heap->head; + for(int i = 0; i < map->size; i++) + { + if(map->array[i].type != M_AVAILABLE + || map->array[i].size < MIN_BLOCK_SIZE) + { + continue; + } + list_block_t *new_block = ((list_block_t*)map->array[i].location) + 1; + set_block(new_block, 1, map->array[i].size - sizeof(list_block_t) * 2, &heap->head, heap->head.prev); + set_block_next(heap->head.prev, new_block); + set_block_prev(&heap->head, new_block); + (new_block - 1)->free = 0; + (block_end_ptr(new_block) + 1)->free = 0; + } + return 0; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 492e40c..3bb0510 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,9 +1,12 @@ if BUILD_TESTS - noinst_PROGRAMS = test_bitmapalloc test_buddyalloc + noinst_PROGRAMS = test_bitmapalloc test_buddyalloc test_listalloc test_bitmapalloc_SOURCES = test_bitmapalloc.c test_bitmapalloc_LDADD = ../src/libmalloc.a test_buddyalloc_SOURCES = test_buddyalloc.c test_buddyalloc_LDADD = ../src/libmalloc.a + + test_listalloc_SOURCES = test_listalloc.c + test_listalloc_LDADD = ../src/libmalloc.a endif \ No newline at end of file diff --git a/tests/test_listalloc b/tests/test_listalloc new file mode 100755 index 0000000..ec9b755 Binary files /dev/null and b/tests/test_listalloc differ diff --git a/tests/test_listalloc.c b/tests/test_listalloc.c new file mode 100644 index 0000000..766bcf8 --- /dev/null +++ b/tests/test_listalloc.c @@ -0,0 +1,109 @@ +#include "libmalloc/list_alloc.h" +#include +#include +#include +#include + +typedef struct memblock_t +{ + unsigned long size; + void *p; +} memblock_t; + +void check_block_list(void *heap, unsigned long heap_size, memblock_t *blocks, unsigned long count) +{ + for (int j = 0; j < count; j++) + { + if (blocks[j].size > 0) + { + assert(blocks[j].p >= heap); + assert(blocks[j].p + blocks[j].size <= heap + heap_size); + for (int k = j + 1; k < count; k++) + { + if (blocks[k].size > 0) + { + // printf("j = (%p, %lu), k = (%p, %lu)\n", blocks[j].p, blocks[j].size, blocks[k].p, blocks[k].size); + assert(blocks[k].p < blocks[j].p || blocks[k].p >= blocks[j].p + blocks[j].size); + assert(blocks[j].p < blocks[k].p || blocks[j].p >= blocks[k].p + blocks[k].size); + } + } + } + } +} + +int main(int argc, char** argv) +{ + unsigned int max_block_count = 0; + unsigned int heap_size = 0; + unsigned int passes = 0; + + char c; + while((c = getopt(argc, argv, "m:b:c:")) != -1) + { + if(c == 'm') + { + sscanf(optarg, "%i", &heap_size); + heap_size *= 1024; + } + else if(c == 'b') + { + sscanf(optarg, "%i", &max_block_count); + } + else if(c == 'c') + { + sscanf(optarg, "%i", &passes); + } + } + + printf("Running test with %i byte heap, %i blocks, %i passes.\n", + heap_size, max_block_count, passes); + + void *heap = malloc(heap_size); + memory_map_t map = { + .array = malloc(sizeof(unsigned long) * 16), + .capacity = 16, + .size = 0 + }; + memmap_insert_region(&map, heap, heap_size, M_AVAILABLE); + + list_alloc_descriptor_t desc; + list_alloc_init(&desc, &map); + memblock_t *blocks = calloc(max_block_count, sizeof(memblock_t)); + + for(int i = 0; i < passes; i++) + { + int index = rand() % max_block_count; + if(blocks[index].size == 0) + { + unsigned long size = rand() % 65536 + 1; + blocks[index].p = list_alloc_reserve(&desc, size); + //printf("Reserved %lu bytes.\n", size); + if(blocks[index].p != NOMEM) + { + blocks[index].size = size; + } + else + { + printf("Out of memory trying to reserve %lu bytes\n", size); + } + } + else + { + list_alloc_free(&desc, blocks[index].p); + //printf("Freed %p\n", blocks[index].p); + blocks[index].size = 0; + } + check_block_list(heap, heap_size, blocks, max_block_count); + } + + for(int i = 0; i < max_block_count; i++) + { + if(blocks[i].size != 0) + { + list_alloc_free(&desc, blocks[i].p); + blocks[i].size = 0; + } + } + + return 0; +} \ No newline at end of file