(memory): returning pages back when freeing memory
This commit is contained in:
parent
4d34312748
commit
f855d910ed
2 changed files with 99 additions and 36 deletions
|
|
@ -85,7 +85,7 @@ void *kmalloc(size_t size)
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
size = align_up(size, 8);
|
size = align_up(size, 16);
|
||||||
|
|
||||||
if (heap_free_list == NULL)
|
if (heap_free_list == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -114,13 +114,7 @@ void *kmalloc(size_t size)
|
||||||
HeapHeader *header = (HeapHeader *)page_alloc();
|
HeapHeader *header = (HeapHeader *)page_alloc();
|
||||||
header->size = PAGE_SIZE - sizeof(HeapHeader);
|
header->size = PAGE_SIZE - sizeof(HeapHeader);
|
||||||
header->is_free = 1;
|
header->is_free = 1;
|
||||||
header->next = heap_free_list;
|
kheap_insert_sorted(header);
|
||||||
header->prev = NULL;
|
|
||||||
if (heap_free_list)
|
|
||||||
{
|
|
||||||
heap_free_list->prev = header;
|
|
||||||
}
|
|
||||||
heap_free_list = header;
|
|
||||||
current = header;
|
current = header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,26 +125,7 @@ void *kmalloc(size_t size)
|
||||||
|
|
||||||
current->is_free = 0;
|
current->is_free = 0;
|
||||||
|
|
||||||
size_t min_split_size = sizeof(HeapHeader) + 16;
|
kheap_split(current, size);
|
||||||
if (current->size >= size + min_split_size)
|
|
||||||
{
|
|
||||||
HeapHeader *new_header = (HeapHeader *)((uint8_t *)current + sizeof(HeapHeader) + size);
|
|
||||||
if ((uintptr_t)new_header < 0x80000000 || (uintptr_t)new_header > 0x88000000)
|
|
||||||
{
|
|
||||||
kpanic("Splitting created invalid pointer: %x!", (uint64_t)new_header);
|
|
||||||
}
|
|
||||||
new_header->size = current->size - size - sizeof(HeapHeader);
|
|
||||||
new_header->is_free = 1;
|
|
||||||
|
|
||||||
new_header->next = current->next;
|
|
||||||
new_header->prev = current;
|
|
||||||
if (current->next)
|
|
||||||
{
|
|
||||||
current->next->prev = new_header;
|
|
||||||
}
|
|
||||||
current->size = size;
|
|
||||||
current->next = new_header;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (void *)((char *)current + sizeof(HeapHeader));
|
return (void *)((char *)current + sizeof(HeapHeader));
|
||||||
}
|
}
|
||||||
|
|
@ -167,13 +142,57 @@ void kfree(void *ptr)
|
||||||
}
|
}
|
||||||
header->is_free = 1;
|
header->is_free = 1;
|
||||||
|
|
||||||
kcoalesce(header);
|
HeapHeader *final_block = kcoalesce(header);
|
||||||
|
uintptr_t block_start = (uintptr_t)final_block;
|
||||||
|
uintptr_t block_end = block_start + sizeof(HeapHeader) + final_block->size;
|
||||||
|
uintptr_t first_page = align_up((uintptr_t)block_start + sizeof(HeapHeader), PAGE_SIZE);
|
||||||
|
uintptr_t last_page = align_down((uintptr_t)block_end, PAGE_SIZE);
|
||||||
|
|
||||||
|
if (first_page < last_page)
|
||||||
|
{
|
||||||
|
if (block_start < first_page)
|
||||||
|
{
|
||||||
|
kheap_split(final_block, first_page - block_start - sizeof(HeapHeader));
|
||||||
|
final_block = final_block->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kcoalesce(HeapHeader *header)
|
size_t data_to_free = last_page - (uintptr_t)final_block - sizeof(HeapHeader);
|
||||||
|
|
||||||
|
kheap_split(final_block, data_to_free);
|
||||||
|
|
||||||
|
if (final_block->prev)
|
||||||
|
final_block->prev->next = final_block->next;
|
||||||
|
if (final_block->next)
|
||||||
|
final_block->next->prev = final_block->prev;
|
||||||
|
if (final_block == heap_free_list)
|
||||||
|
heap_free_list = final_block->next;
|
||||||
|
|
||||||
|
for (uintptr_t addr = first_page; addr < last_page; addr += PAGE_SIZE)
|
||||||
|
{
|
||||||
|
page_free((void *)addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapHeader *kcoalesce(HeapHeader *header)
|
||||||
{
|
{
|
||||||
if (!header || !header->is_free)
|
if (!header || !header->is_free)
|
||||||
return;
|
return header;
|
||||||
|
|
||||||
|
// walk back
|
||||||
|
while (header->prev && header->prev->is_free)
|
||||||
|
{
|
||||||
|
uintptr_t prev_end = (uintptr_t)header->prev + sizeof(HeapHeader) + header->prev->size;
|
||||||
|
if (prev_end == (uintptr_t)header)
|
||||||
|
{
|
||||||
|
header = header->prev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// merge forward
|
// merge forward
|
||||||
while (header->next && header->next->is_free)
|
while (header->next && header->next->is_free)
|
||||||
{
|
{
|
||||||
|
|
@ -192,15 +211,57 @@ void kcoalesce(HeapHeader *header)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
if (header->prev && header->prev->is_free)
|
void kheap_split(HeapHeader *header, size_t size)
|
||||||
{
|
{
|
||||||
uintptr_t prev_end = (uintptr_t)header->prev + sizeof(HeapHeader) + header->prev->size;
|
size = align_up(size, 16);
|
||||||
if (prev_end == (uintptr_t)header)
|
size_t min_split_size = sizeof(HeapHeader) + 16;
|
||||||
|
if (header->size >= size + min_split_size)
|
||||||
{
|
{
|
||||||
kcoalesce(header->prev);
|
HeapHeader *new_header = (HeapHeader *)((uint8_t *)header + sizeof(HeapHeader) + size);
|
||||||
|
if ((uintptr_t)new_header < 0x80000000 || (uintptr_t)new_header > 0x88000000)
|
||||||
|
{
|
||||||
|
kpanic("Splitting created invalid pointer: %x!", (uint64_t)new_header);
|
||||||
|
}
|
||||||
|
new_header->size = header->size - size - sizeof(HeapHeader);
|
||||||
|
new_header->is_free = 1;
|
||||||
|
|
||||||
|
new_header->next = header->next;
|
||||||
|
new_header->prev = header;
|
||||||
|
if (header->next)
|
||||||
|
{
|
||||||
|
header->next->prev = new_header;
|
||||||
|
}
|
||||||
|
header->size = size;
|
||||||
|
header->next = new_header;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kheap_insert_sorted(HeapHeader *new_block)
|
||||||
|
{
|
||||||
|
if (heap_free_list == NULL || (uintptr_t)new_block < (uintptr_t)heap_free_list)
|
||||||
|
{
|
||||||
|
new_block->next = heap_free_list;
|
||||||
|
if (heap_free_list)
|
||||||
|
heap_free_list->prev = new_block;
|
||||||
|
heap_free_list = new_block;
|
||||||
|
new_block->prev = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapHeader *curr = heap_free_list;
|
||||||
|
while (curr->next != NULL && (uintptr_t)curr->next < (uintptr_t)new_block)
|
||||||
|
{
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_block->next = curr->next;
|
||||||
|
new_block->prev = curr;
|
||||||
|
if (curr->next)
|
||||||
|
curr->next->prev = new_block;
|
||||||
|
curr->next = new_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_memory_integrity()
|
void test_memory_integrity()
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,10 @@ void page_init();
|
||||||
void page_free(void *addr);
|
void page_free(void *addr);
|
||||||
void *page_alloc();
|
void *page_alloc();
|
||||||
void *kmalloc(size_t size);
|
void *kmalloc(size_t size);
|
||||||
|
void kheap_split(HeapHeader *header, size_t size);
|
||||||
|
void kheap_insert_sorted(HeapHeader *new_block);
|
||||||
void kfree(void *ptr);
|
void kfree(void *ptr);
|
||||||
void kcoalesce(HeapHeader *header);
|
HeapHeader *kcoalesce(HeapHeader *header);
|
||||||
void test_memory_integrity();
|
void test_memory_integrity();
|
||||||
void test_memory_alignment();
|
void test_memory_alignment();
|
||||||
void test_memory_stress();
|
void test_memory_stress();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue