Files
frostbyte/src/heap.c
T

146 lines
3.1 KiB
C

#include "heap.h"
#include "string.h"
typedef struct Block {
usize size;
struct Block* prev;
struct Block* next;
uint64 free;
} Block;
static uint64 heapBase;
static uint64 heapLimit;
static Block* head;
static uint64 alignUp(uint64 value, uint64 alignment)
{
return (value + alignment - 1) & ~(alignment - 1);
}
void heapInit(uint64 start, uint64 size)
{
heapBase = alignUp(start, 16);
heapLimit = start + size;
head = (Block*)heapBase;
head->size = (heapLimit - heapBase) - sizeof(Block);
head->prev = nullptr;
head->next = nullptr;
head->free = 1;
}
static void split(Block* block, usize wanted)
{
if (block->size < wanted + sizeof(Block) + 16)
return;
Block* rest = (Block*)((uint8*)block + sizeof(Block) + wanted);
rest->size = block->size - wanted - sizeof(Block);
rest->free = 1;
rest->prev = block;
rest->next = block->next;
if (block->next)
block->next->prev = rest;
block->next = rest;
block->size = wanted;
}
void* kmalloc(usize size)
{
if (size == 0)
size = 16;
usize wanted = alignUp(size, 16);
for (Block* block = head; block; block = block->next) {
if (block->free && block->size >= wanted) {
split(block, wanted);
block->free = 0;
return (uint8*)block + sizeof(Block);
}
}
return nullptr;
}
void kfree(void* pointer)
{
if (!pointer)
return;
Block* block = (Block*)((uint8*)pointer - sizeof(Block));
block->free = 1;
if (block->next && block->next->free) {
Block* victim = block->next;
block->size += sizeof(Block) + victim->size;
block->next = victim->next;
if (victim->next)
victim->next->prev = block;
}
if (block->prev && block->prev->free) {
Block* keep = block->prev;
keep->size += sizeof(Block) + block->size;
keep->next = block->next;
if (block->next)
block->next->prev = keep;
}
}
void* krealloc(void* pointer, usize size)
{
if (!pointer)
return kmalloc(size);
if (size == 0) {
kfree(pointer);
return nullptr;
}
Block* block = (Block*)((uint8*)pointer - sizeof(Block));
usize wanted = alignUp(size, 16);
if (block->size >= wanted)
return pointer;
void* fresh = kmalloc(size);
if (!fresh)
return nullptr;
memcpy(fresh, pointer, block->size);
kfree(pointer);
return fresh;
}
uint64 heapFreeBytes(void)
{
uint64 total = 0;
for (Block* block = head; block; block = block->next)
if (block->free)
total += block->size;
return total;
}
uint64 heapLargestFree(void)
{
uint64 largest = 0;
for (Block* block = head; block; block = block->next)
if (block->free && block->size > largest)
largest = block->size;
return largest;
}
uint64 heapBlockCount(void)
{
uint64 count = 0;
for (Block* block = head; block; block = block->next)
count++;
return count;
}
uint64 heapTotal(void)
{
return heapLimit - heapBase;
}
uint64 heapUsed(void)
{
return heapTotal() - heapFreeBytes();
}