Added new list-based memory allocator

This commit is contained in:
2023-08-30 22:49:43 -05:00
parent 9f41a1bd7f
commit 64ad489b90
7 changed files with 276 additions and 3 deletions

View File

@@ -1,2 +1,2 @@
nobase_include_HEADERS = libmalloc/bitmap_alloc.h libmalloc/buddy_alloc.h \ nobase_include_HEADERS = libmalloc/bitmap_alloc.h libmalloc/buddy_alloc.h \
libmalloc/memmap.h libmalloc/common.h libmalloc/list_alloc.h libmalloc/memmap.h libmalloc/common.h

View File

@@ -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

View File

@@ -1,4 +1,4 @@
lib_LIBRARIES = libmalloc.a 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 libmalloc_a_CFLAGS = -I$(prefix)/include

134
src/list_alloc.c Normal file
View File

@@ -0,0 +1,134 @@
#include "libmalloc/list_alloc.h"
#include <stddef.h>
#include <stdio.h>
#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;
}

View File

@@ -1,9 +1,12 @@
if BUILD_TESTS 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_SOURCES = test_bitmapalloc.c
test_bitmapalloc_LDADD = ../src/libmalloc.a test_bitmapalloc_LDADD = ../src/libmalloc.a
test_buddyalloc_SOURCES = test_buddyalloc.c test_buddyalloc_SOURCES = test_buddyalloc.c
test_buddyalloc_LDADD = ../src/libmalloc.a test_buddyalloc_LDADD = ../src/libmalloc.a
test_listalloc_SOURCES = test_listalloc.c
test_listalloc_LDADD = ../src/libmalloc.a
endif endif

BIN
tests/test_listalloc Executable file

Binary file not shown.

109
tests/test_listalloc.c Normal file
View File

@@ -0,0 +1,109 @@
#include "libmalloc/list_alloc.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
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;
}