From 4ceebe15d8f261d864d2bc88e2f922228bdc445d Mon Sep 17 00:00:00 2001 From: Nathan Giddings Date: Sat, 1 Aug 2020 19:45:35 -0500 Subject: [PATCH] Started work on a memory allocator --- src/allocator.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++++++ src/allocator.hpp | 40 +++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/allocator.cpp create mode 100644 src/allocator.hpp diff --git a/src/allocator.cpp b/src/allocator.cpp new file mode 100644 index 0000000..cc24587 --- /dev/null +++ b/src/allocator.cpp @@ -0,0 +1,97 @@ +#include "allocator.hpp" + +#define AVAIL 0 +#define UNAVAIL -1 + +inline size_t ilog2(size_t n) +{ + size_t m = n; + size_t count = 0; + bool isPowerOfTwo = true; + while(m) + { + if((m & 1) == 1 && m > 1) + { + isPowerOfTwo = false; + } + count++; + m >>= 1; + } + return count - (isPowerOfTwo ? 1 : 0); +} + +kernel::Allocator::Allocator(void* base, size_t heapSize, size_t blockSize) +{ + this->base = (char*) base; + this->heapSize = heapSize; + this->blockSize = blockSize; + this->treeHeight = ilog2(heapSize / blockSize); + size_t headerSize = (heapSize / blockSize) << 1; + for(size_t i = 1; i < (heapSize / blockSize) * 2; i++) + this->base[i] = UNAVAIL; + for(size_t i = 0; i < heapSize / blockSize; i++) + { + if(blockSize * i >= headerSize) + { + size_t index = i + (1 << treeHeight); + this->base[index] = AVAIL; + for(; index > 1 && this->base[index ^ 1] == 0; index >>= 1) + { + this->base[index] = UNAVAIL; + this->base[index ^ 1] = UNAVAIL; + this->base[index >> 1] = AVAIL; + } + } + else + { + this->base[i + (1 << treeHeight)] = 1; + } + } +} + +void* kernel::Allocator::allocate(size_t size) +{ + size += blockSize - 1; + size -= size % blockSize; + size_t height = ilog2(size / blockSize); + size_t index = findFreeBlock(height); + if(index) + { + base[index] = height + 1; + return (void*) ((size_t) base + (blockSize << height) * (index - (1 << (treeHeight - height)))); + } + return NULL; +} + +void kernel::Allocator::free(void* location) +{ + size_t offset = (size_t) location - (size_t) base; + size_t index = (offset / blockSize) + (1 << treeHeight); + for(; index > 0 && base[index] == UNAVAIL; index >>= 1); + base[index] = AVAIL; + for(; index > 1 && base[index ^ 1] == AVAIL; index >>= 1) + { + base[index] = UNAVAIL; + base[index ^ 1] = UNAVAIL; + base[index >> 1] = AVAIL; + } +} + +size_t kernel::Allocator::findFreeBlock(size_t height) +{ + if(height > treeHeight) + return 0; + for(size_t index = 1 << (treeHeight - height); index < 1 << (treeHeight - height + 1); index++) + { + if(base[index] == AVAIL) + return index; + } + size_t index = findFreeBlock(height + 1); + if(index) + { + base[index] = UNAVAIL; + base[index << 1] = AVAIL; + base[(index << 1) ^ 1] = AVAIL; + } + return index << 1; +} \ No newline at end of file diff --git a/src/allocator.hpp b/src/allocator.hpp new file mode 100644 index 0000000..5e99c11 --- /dev/null +++ b/src/allocator.hpp @@ -0,0 +1,40 @@ +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include + +namespace kernel +{ + +class Allocator +{ +public: + + /** + * @param base A pointer to the start of the heap. + * @param heapSize The size of the heap, in bytes. Must be a power of two. + * @param blockSize The smallest unit of allocation, in bytes. Must be a power of two less than or equal to heapSize. + */ + Allocator(void* base, size_t heapSize, size_t blockSize); + + void* allocate(size_t size); + + void free(void* location); + +private: + + size_t findFreeBlock(size_t height); + + char* base; + + size_t heapSize; + + size_t blockSize; + + size_t treeHeight; + +}; + +} + +#endif \ No newline at end of file