linear heap allocator: use rbtree to store allocation size information
This commit is contained in:
parent
550f690c8d
commit
4219a23ebd
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user