mirror of
https://gitee.com/anod/open_agb_firm.git
synced 2025-05-06 22:04:10 +08:00
155 lines
3.1 KiB
C++
155 lines
3.1 KiB
C++
#include "mem_pool.h"
|
|
|
|
/*
|
|
// This method is currently unused
|
|
void MemPool::CoalesceLeft(MemBlock* b)
|
|
{
|
|
auto curPtr = b->base;
|
|
for (auto p = b->prev; p; p = p->prev)
|
|
{
|
|
if ((p->base + p->size) != curPtr) break;
|
|
curPtr = p->base;
|
|
p->size += b->size;
|
|
DelBlock(b);
|
|
b = p;
|
|
}
|
|
}
|
|
*/
|
|
|
|
void MemPool::CoalesceRight(MemBlock* b)
|
|
{
|
|
auto curPtr = b->base + b->size;
|
|
auto next = b->next;
|
|
for (auto n = next; n; n = next)
|
|
{
|
|
next = n->next;
|
|
if (n->base != curPtr) break;
|
|
b->size += n->size;
|
|
curPtr += n->size;
|
|
DelBlock(n);
|
|
}
|
|
}
|
|
|
|
bool MemPool::Allocate(MemChunk& chunk, u32 size, int align)
|
|
{
|
|
// Don't shift out of bounds (CERT INT34-C)
|
|
if(align >= 32 || align < 0)
|
|
return false;
|
|
|
|
// Alignment must not be 0
|
|
if(align == 0)
|
|
return false;
|
|
|
|
u32 alignMask = (1 << align) - 1;
|
|
|
|
// Check if size doesn't fit neatly in alignment
|
|
if(size & alignMask)
|
|
{
|
|
// Make sure addition won't overflow (CERT INT30-C)
|
|
if(size > UINT32_MAX - alignMask)
|
|
return false;
|
|
|
|
// Pad size to next alignment
|
|
size = (size + alignMask) &~ alignMask;
|
|
}
|
|
|
|
// Find the first suitable block
|
|
for (auto b = first; b; b = b->next)
|
|
{
|
|
auto addr = b->base;
|
|
u32 begWaste = (u32)addr & alignMask;
|
|
if (begWaste > 0) begWaste = alignMask + 1 - begWaste;
|
|
if (begWaste > b->size) continue;
|
|
addr += begWaste;
|
|
u32 bSize = b->size - begWaste;
|
|
if (bSize < size) continue;
|
|
|
|
// Found space!
|
|
chunk.addr = addr;
|
|
chunk.size = size;
|
|
|
|
// Resize the block
|
|
if (!begWaste)
|
|
{
|
|
b->base += size;
|
|
b->size -= size;
|
|
if (!b->size)
|
|
DelBlock(b);
|
|
} else
|
|
{
|
|
auto nAddr = addr + size;
|
|
auto nSize = bSize - size;
|
|
b->size = begWaste;
|
|
if (nSize)
|
|
{
|
|
// We need to add the tail chunk that wasn't used to the list
|
|
auto n = MemBlock::Create(nAddr, nSize);
|
|
if (n) InsertAfter(b, n);
|
|
else chunk.size += nSize; // we have no choice but to waste the space.
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void MemPool::Deallocate(const MemChunk& chunk)
|
|
{
|
|
u8* cAddr = chunk.addr;
|
|
auto cSize = chunk.size;
|
|
bool done = false;
|
|
|
|
// Try to merge the chunk somewhere into the list
|
|
for (auto b = first; !done && b; b = b->next)
|
|
{
|
|
auto addr = b->base;
|
|
if (addr > cAddr)
|
|
{
|
|
if ((cAddr + cSize) == addr)
|
|
{
|
|
// Merge the chunk to the left of the block
|
|
b->base = cAddr;
|
|
b->size += cSize;
|
|
} else
|
|
{
|
|
// We need to insert a new block
|
|
auto c = MemBlock::Create(cAddr, cSize);
|
|
if (c) InsertBefore(b, c);
|
|
}
|
|
done = true;
|
|
} else if ((b->base + b->size) == cAddr)
|
|
{
|
|
// Coalesce to the right
|
|
b->size += cSize;
|
|
CoalesceRight(b);
|
|
done = true;
|
|
}
|
|
}
|
|
|
|
if (!done)
|
|
{
|
|
// Either the list is empty or the chunk address is past the end
|
|
// address of the last block -- let's add a new block at the end
|
|
auto b = MemBlock::Create(cAddr, cSize);
|
|
if (b) AddBlock(b);
|
|
}
|
|
}
|
|
|
|
/*
|
|
void MemPool::Dump(const char* title)
|
|
{
|
|
printf("<%s> VRAM Pool Dump\n", title);
|
|
for (auto b = first; b; b = b->next)
|
|
printf(" - %p (%u bytes)\n", b->base, b->size);
|
|
}
|
|
*/
|
|
|
|
u32 MemPool::GetFreeSpace()
|
|
{
|
|
u32 acc = 0;
|
|
for (auto b = first; b; b = b->next)
|
|
acc += b->size;
|
|
return acc;
|
|
}
|