Files
RetroArch/os/ctr/ctr_memory.c
T
LibretroAdmin bae87174dc 3DS: the runtime moves to os/ctr, linear allocator in C
The tree's 3DS layer (the custom crt0 and link spec, system and memory
setup, svchax, the old GPU command layer and the 3dsx/CIA launchers)
lives under os/ctr, beside os/gekko and os/wiiu.

The linear heap allocator is C: the same first-fit pool, so buffers
land where they did, with live allocations found by address in an
open-addressing table instead of a per-allocation tree node, and list
nodes taken from cache-line-aligned slabs and reused. On the same
trace it runs about half the instructions and practically no
malloc/free calls. With the whole heap allocated, a further allocation
now fails instead of starting the heap over and handing out its first
address again, and the free-space queries no longer fault.

samples/frontend/ctr_linear checks placement, alignment, coalescing,
the full-heap case and pages handed back from the heap's end.
2026-10-29 18:10:30 +01:00

155 lines
3.6 KiB
C

#include <3ds.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include "ctr_debug.h"
extern u32 __heapBase;
extern u32 __heap_size;
extern u32 __stack_bottom;
extern u32 __stack_size_extra;
extern u32 __stacksize__;
u32 ctr_get_linear_free(void);
u32 ctr_get_linear_unused(void);
u32 ctr_get_stack_free(void)
{
extern u32 __stack_bottom;
uint32_t* stack_bottom_current = (u32*)__stack_bottom;
while(*stack_bottom_current++ == 0xFCFCFCFC);
stack_bottom_current--;
return ((u32)stack_bottom_current - __stack_bottom);
}
u32 ctr_get_stack_usage(void)
{
extern u32 __stacksize__;
u32 stack_free = ctr_get_stack_free();
return __stacksize__ > stack_free? __stacksize__ - stack_free: 0;
}
void ctr_linear_free_pages(u32 pages);
void ctr_free_pages(u32 pages)
{
u32 linear_free_pages;
u32 stack_free, stack_usage, stack_free_pages;
if (!pages)
return;
linear_free_pages = ctr_get_linear_free() >> 12;
if ((ctr_get_linear_unused() >> 12) > pages + 0x100)
return ctr_linear_free_pages(pages);
#if 0
if (linear_free_pages > pages + 0x400)
return ctr_linear_free_pages(pages);
#endif
stack_free = ctr_get_stack_free();
stack_usage = __stacksize__ > stack_free
? __stacksize__ - stack_free
: 0;
stack_free = stack_free > __stack_size_extra
? __stack_size_extra
: stack_free;
stack_free_pages = stack_free >> 12;
if (linear_free_pages + (stack_free_pages - (stack_usage >> 12)) > pages)
{
stack_free_pages -= (stack_usage >> 12);
stack_free_pages = stack_free_pages > pages ? pages : stack_free_pages;
linear_free_pages = pages - stack_free_pages;
}
else if (linear_free_pages + stack_free_pages > pages)
stack_free_pages = pages - linear_free_pages;
else
return;
if (linear_free_pages)
ctr_linear_free_pages(linear_free_pages);
if (stack_free_pages)
{
u32 tmp;
svcControlMemory(&tmp, __stack_bottom,
0x0,
stack_free_pages << 12,
MEMOP_FREE, MEMPERM_READ | MEMPERM_WRITE);
__stack_bottom += stack_free_pages << 12;
__stack_size_extra -= stack_free_pages << 12;
__stacksize__ -= stack_free_pages << 12;
#if 0
printf("s:0x%08X-->0x%08X(-0x%08X) \n", stack_free,
stack_free - (stack_free_pages << 12),
stack_free_pages << 12);
DEBUG_HOLD();
#endif
}
}
u32 ctr_get_free_space(void)
{
s64 mem_used;
u32 app_memory = *((u32*)0x1FF80040);
svcGetSystemInfo(&mem_used, 0, 1);
return app_memory - (u32)mem_used;
}
void ctr_request_free_pages(u32 pages)
{
u32 free_pages = ctr_get_free_space() >> 12;
if (pages > free_pages)
{
ctr_free_pages(pages - free_pages);
free_pages = ctr_get_free_space() >> 12;
}
}
void* _sbrk_r(struct _reent *ptr, ptrdiff_t incr)
{
static u32 sbrk_top = 0;
u32 tmp;
int diff;
if (!sbrk_top)
sbrk_top = __heapBase;
diff = ((sbrk_top + incr + 0xFFF) & ~0xFFF)
- (__heapBase + __heap_size);
if (diff > 0)
{
ctr_request_free_pages(diff >> 12);
if (svcControlMemory(&tmp, __heapBase + __heap_size,
0x0, diff, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE) < 0)
{
ptr->_errno = ENOMEM;
return (caddr_t) -1;
}
}
__heap_size += diff;
while (diff < 0) {
int size = -diff < 0x100000 ? -diff : 0x100000;
diff += size;
svcControlMemory(&tmp, __heapBase + __heap_size - diff,
0x0, size, MEMOP_FREE, 0);
}
sbrk_top += incr;
return (caddr_t)(sbrk_top - incr);
}