2009-12-04 16:05:20 +01:00
|
|
|
|
|
|
|
#include "mem2alloc.h"
|
|
|
|
|
|
|
|
#include <ogc/system.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
class LockMutex
|
|
|
|
{
|
|
|
|
mutex_t &m_mutex;
|
2009-12-04 16:05:20 +01:00
|
|
|
public:
|
2010-02-09 11:59:55 +01:00
|
|
|
LockMutex(mutex_t &m) : m_mutex(m) { LWP_MutexLock(m_mutex); }
|
|
|
|
~LockMutex(void) { LWP_MutexUnlock(m_mutex); }
|
2009-12-04 16:05:20 +01:00
|
|
|
};
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void CMEM2Alloc::init(unsigned int size)
|
|
|
|
{
|
|
|
|
m_baseAddress = (SBlock *)(((u32)SYS_GetArena2Lo() + 31) & ~31);
|
|
|
|
m_endAddress = (SBlock *)((char *)m_baseAddress + std::min(size * 0x100000, SYS_GetArena2Size() & ~31));
|
|
|
|
if (m_endAddress > (SBlock *)0x93000000) // See loader/disc.c
|
|
|
|
m_endAddress = (SBlock *)0x93000000;
|
|
|
|
SYS_SetArena2Lo(m_endAddress);
|
|
|
|
LWP_MutexInit(&m_mutex, 0);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void CMEM2Alloc::init(void *addr, void *end)
|
|
|
|
{
|
|
|
|
m_baseAddress = (SBlock *)(((u32)addr + 31) & ~31);
|
|
|
|
m_endAddress = (SBlock *)((u32)end & ~31);
|
|
|
|
LWP_MutexInit(&m_mutex, 0);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void CMEM2Alloc::cleanup(void)
|
|
|
|
{
|
|
|
|
LWP_MutexDestroy(m_mutex);
|
|
|
|
m_mutex = 0;
|
|
|
|
m_first = 0;
|
2009-12-04 16:05:20 +01:00
|
|
|
// // Try to release the range we took through SYS functions
|
|
|
|
// if (SYS_GetArena2Lo() == m_endAdress)
|
|
|
|
// SYS_SetArena2Lo(m_baseAddress);
|
2010-02-09 11:59:55 +01:00
|
|
|
m_baseAddress = 0;
|
|
|
|
m_endAddress = 0;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void CMEM2Alloc::clear(void)
|
|
|
|
{
|
|
|
|
m_first = 0;
|
|
|
|
memset(m_baseAddress, 0, (u8 *)m_endAddress - (u8 *)m_endAddress);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
unsigned int CMEM2Alloc::usableSize(void *p)
|
|
|
|
{
|
|
|
|
return p == 0 ? 0 : ((SBlock *)p - 1)->s * sizeof (SBlock);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void *CMEM2Alloc::allocate(unsigned int s)
|
|
|
|
{
|
|
|
|
if (s == 0)
|
|
|
|
s = 1;
|
|
|
|
//
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
//
|
|
|
|
s = (s - 1) / sizeof (SBlock) + 1;
|
|
|
|
// First block
|
|
|
|
if (m_first == 0)
|
|
|
|
{
|
|
|
|
if (m_baseAddress + s + 1 >= m_endAddress)
|
|
|
|
return 0;
|
|
|
|
m_first = m_baseAddress;
|
|
|
|
m_first->next = 0;
|
|
|
|
m_first->prev = 0;
|
|
|
|
m_first->s = s;
|
|
|
|
m_first->f = false;
|
|
|
|
return (void *)(m_first + 1);
|
|
|
|
}
|
|
|
|
// Search for a free block
|
|
|
|
SBlock *i;
|
|
|
|
SBlock *j;
|
|
|
|
for (i = m_first; i != 0; i = i->next)
|
|
|
|
{
|
|
|
|
if (i->f && i->s >= s)
|
|
|
|
break;
|
|
|
|
j = i;
|
|
|
|
}
|
|
|
|
// Create a new block
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
i = j + j->s + 1;
|
|
|
|
if (i + s + 1 >= m_endAddress)
|
|
|
|
return 0;
|
|
|
|
j->next = i;
|
|
|
|
i->prev = j;
|
|
|
|
i->next = 0;
|
|
|
|
i->s = s;
|
|
|
|
i->f = false;
|
|
|
|
return (void *)(i + 1);
|
|
|
|
}
|
|
|
|
// Reuse a free block
|
|
|
|
i->f = false;
|
|
|
|
// Split it
|
|
|
|
if (i->s > s + 1)
|
|
|
|
{
|
|
|
|
j = i + s + 1;
|
|
|
|
j->f = true;
|
|
|
|
j->s = i->s - s - 1;
|
|
|
|
i->s = s;
|
|
|
|
j->next = i->next;
|
|
|
|
j->prev = i;
|
|
|
|
i->next = j;
|
|
|
|
if (j->next != 0)
|
|
|
|
j->next->prev = j;
|
|
|
|
}
|
|
|
|
return (void *)(i + 1);
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void CMEM2Alloc::release(void *p)
|
|
|
|
{
|
|
|
|
if (p == 0)
|
|
|
|
return;
|
|
|
|
LockMutex lock(m_mutex);
|
|
|
|
SBlock *i = (SBlock *)p - 1;
|
|
|
|
i->f = true;
|
|
|
|
// Merge with previous block
|
|
|
|
if (i->prev != 0 && i->prev->f)
|
|
|
|
{
|
|
|
|
i = i->prev;
|
|
|
|
i->s += i->next->s + 1;
|
|
|
|
i->next = i->next->next;
|
|
|
|
if (i->next != 0)
|
|
|
|
i->next->prev = i;
|
|
|
|
}
|
|
|
|
// Merge with next block
|
|
|
|
if (i->next != 0 && i->next->f)
|
|
|
|
{
|
|
|
|
i->s += i->next->s + 1;
|
|
|
|
i->next = i->next->next;
|
|
|
|
if (i->next != 0)
|
|
|
|
i->next->prev = i;
|
|
|
|
}
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
void *CMEM2Alloc::reallocate(void *p, unsigned int s)
|
|
|
|
{
|
|
|
|
SBlock *i;
|
|
|
|
SBlock *j;
|
|
|
|
void *n;
|
2009-12-04 16:05:20 +01:00
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
if (s == 0)
|
|
|
|
s = 1;
|
|
|
|
if (p == 0)
|
|
|
|
return allocate(s);
|
|
|
|
i = (SBlock *)p - 1;
|
|
|
|
s = (s - 1) / sizeof (SBlock) + 1;
|
|
|
|
{
|
|
|
|
LockMutex lock(m_mutex);
|
2010-02-15 00:22:52 +01:00
|
|
|
if (i + s + 1 >= m_endAddress)
|
|
|
|
return 0;
|
|
|
|
|
2010-02-09 11:59:55 +01:00
|
|
|
// Last block
|
|
|
|
if (i->next == 0 && i + s + 1 < m_endAddress)
|
|
|
|
{
|
|
|
|
i->s = s;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
// Size <= current size + next block
|
|
|
|
if (i->s < s && i->next->f && i->s + i->next->s + 1 >= s)
|
|
|
|
{
|
|
|
|
// Merge
|
|
|
|
i->s += i->next->s + 1;
|
|
|
|
i->next = i->next->next;
|
|
|
|
if (i->next != 0)
|
|
|
|
i->next->prev = i;
|
|
|
|
}
|
|
|
|
// Size <= current size
|
|
|
|
if (i->s >= s)
|
|
|
|
{
|
|
|
|
// Split
|
|
|
|
if (i->s > s + 1)
|
|
|
|
{
|
|
|
|
j = i + s + 1;
|
|
|
|
j->f = true;
|
|
|
|
j->s = i->s - s - 1;
|
|
|
|
i->s = s;
|
|
|
|
j->next = i->next;
|
|
|
|
j->prev = i;
|
|
|
|
i->next = j;
|
|
|
|
if (j->next != 0)
|
|
|
|
j->next->prev = j;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Size > current size
|
|
|
|
n = allocate(s * sizeof (SBlock));
|
|
|
|
if (n == 0)
|
|
|
|
return 0;
|
|
|
|
memcpy(n, p, i->s * sizeof (SBlock));
|
|
|
|
release(p);
|
|
|
|
return n;
|
2009-12-04 16:05:20 +01:00
|
|
|
}
|