linear heap allocator: use rbtree to store allocation size information

This commit is contained in:
fincs 2014-11-21 23:44:57 +01:00
parent 550f690c8d
commit 4219a23ebd

View File

@ -1,9 +1,56 @@
#include <3ds.h> #include <3ds.h>
#include <3ds/util/rbtree.h>
#include "mem_pool.h" #include "mem_pool.h"
extern u32 __linear_heap, __linear_heap_size; extern u32 __linear_heap, __linear_heap_size;
static MemPool sLinearPool; static MemPool sLinearPool;
static rbtree_t sAddrMap;
struct addrMapNode
{
rbtree_node node;
MemChunk chunk;
};
#define getAddrMapNode(x) rbtree_item((x), addrMapNode, node)
static int addrMapNodeComparator(const rbtree_node_t* _lhs, const rbtree_node_t* _rhs)
{
auto lhs = getAddrMapNode(_lhs)->chunk.addr;
auto rhs = getAddrMapNode(_rhs)->chunk.addr;
if (lhs < rhs)
return -1;
if (lhs > rhs)
return 1;
return 0;
}
static void addrMapNodeDestructor(rbtree_node_t* a)
{
free(getAddrMapNode(a));
}
static addrMapNode* getNode(void* addr)
{
addrMapNode n;
n.chunk.addr = (u8*)addr;
auto p = rbtree_find(&sAddrMap, &n.node);
return p ? getAddrMapNode(p) : nullptr;
}
static addrMapNode* newNode(const MemChunk& chunk)
{
auto p = (addrMapNode*)malloc(sizeof(addrMapNode));
if (!p) return nullptr;
p->chunk = chunk;
return p;
}
static void delNode(addrMapNode* node)
{
rbtree_remove(&sAddrMap, &node->node, addrMapNodeDestructor);
}
static bool linearInit() static bool linearInit()
{ {
@ -11,6 +58,7 @@ static bool linearInit()
if (blk) if (blk)
{ {
sLinearPool.AddBlock(blk); sLinearPool.AddBlock(blk);
rbtree_init(&sAddrMap, addrMapNodeComparator);
return true; return true;
} }
return false; return false;
@ -36,19 +84,19 @@ void* linearMemAlign(size_t size, size_t alignment)
if (!sLinearPool.Ready() && !linearInit()) if (!sLinearPool.Ready() && !linearInit())
return nullptr; return nullptr;
// Reserve memory for MemChunk structure
size += alignment;
// Allocate the chunk // Allocate the chunk
MemChunk chunk; MemChunk chunk;
if (!sLinearPool.Allocate(chunk, size, shift)) if (!sLinearPool.Allocate(chunk, size, shift))
return nullptr; return nullptr;
// Copy the MemChunk structure and return memory auto node = newNode(chunk);
auto addr = chunk.addr; if (!node)
*(MemChunk*)addr = chunk; {
*(u32*)(addr + alignment - sizeof(u32)) = alignment; sLinearPool.Deallocate(chunk);
return addr + alignment; return nullptr;
}
if (rbtree_insert(&sAddrMap, &node->node));
return chunk.addr;
} }
void* linearAlloc(size_t size) void* linearAlloc(size_t size)
@ -64,10 +112,14 @@ void* linearRealloc(void* mem, size_t size)
void linearFree(void* mem) void linearFree(void* mem)
{ {
// Find MemChunk structure and free the chunk auto node = getNode(mem);
u32 alignment = *((u32*)mem - 1); if (!node) return;
auto pChunk = (MemChunk*)((u8*)mem - alignment);
sLinearPool.Deallocate(*pChunk); // Free the chunk
sLinearPool.Deallocate(node->chunk);
// Free the node
delNode(node);
} }
u32 linearSpaceFree() u32 linearSpaceFree()