power_play/src/base/base_arena.c
2025-08-01 06:29:01 -05:00

155 lines
4.7 KiB
C

SharedScratchCtx shared_scratch_ctx = ZI;
/* NOTE: Application will exit if arena fails to reserve or commit initial memory. */
Arena *AllocArena(u64 reserve)
{
__prof;
reserve += ArenaHeaderSize;
/* Round up to nearest block size */
u64 block_remainder = reserve % ArenaBlockSize;
if (block_remainder > 0)
{
reserve += ArenaBlockSize - block_remainder;
}
u8 *base = ReserveMemory(reserve);
if (!base)
{
/* Hard fail on memory reserve failure for now */
/* FIXME: Enable this */
//P_Panic(Lit("Failed to reserve memory"));
(*(volatile int *)0) = 0;
}
u64 reserved = reserve;
AddGstat(GSTAT_MEMORY_RESERVED, reserve);
/* Commit initial block */
base = CommitMemory(base, ArenaBlockSize);
if (!base)
{
/* Hard fail on commit failure */
/* FIXME: Enable this */
//P_Panic(Lit("Failed to commit initial memory block: System may be out of memory"));
(*(volatile int *)0) = 0;
}
Assert(((u64)base & 0xFFF) == 0); /* Base should be 4k aligned */
StaticAssert(ArenaHeaderSize <= ArenaBlockSize); /* Header must fit in first block */
StaticAssert(sizeof(Arena) <= ArenaHeaderSize); /* Arena struct must fit in header */
__profalloc(base, ArenaBlockSize);
AsanPoison(base + sizeof(Arena), ArenaBlockSize - sizeof(Arena));
AddGstat(GSTAT_MEMORY_COMMITTED, ArenaBlockSize);
AddGstat(GSTAT_NUM_ARENAS, 1);
/* Create & return arena header at beginning of block */
Arena *arena = (Arena *)base;
ZeroStruct(arena);
arena->committed = ArenaBlockSize - ArenaHeaderSize;
arena->reserved = reserved;
return arena;
}
void ReleaseArena(Arena *arena)
{
AsanUnpoison(arena, arena->committed + ArenaHeaderSize);
__prof;
__proffree(arena);
AddGstat(GSTAT_MEMORY_COMMITTED, -(i64)(arena->committed - ArenaHeaderSize));
AddGstat(GSTAT_MEMORY_RESERVED, -(i64)(arena->reserved));
AddGstat(GSTAT_NUM_ARENAS, -1);
ReleaseMemory(arena);
}
/* NOTE: Application will exit if arena fails to commit memory */
void *PushBytesNoZero(Arena *arena, u64 size, u64 align)
{
Assert(align > 0);
Assert(!arena->readonly);
void *ptr = 0;
u8 *base = ArenaBase(arena);
/* Check to avoid aligning when size = 0 */
if (size > 0)
{
u64 aligned_start_pos = (arena->pos + (align - 1));
aligned_start_pos -= aligned_start_pos % align;
u64 new_pos = aligned_start_pos + size;
if (new_pos > arena->committed)
{
__profn("Arena commit");
/* Commit new block(s) */
u64 blocks_needed = (new_pos - arena->committed + ArenaBlockSize - 1) / ArenaBlockSize;
u64 commit_bytes = blocks_needed * ArenaBlockSize;
u64 new_capacity = arena->committed + commit_bytes;
if (new_capacity > arena->reserved)
{
/* Hard fail if we overflow reserved memory for now */
/* FIXME: Enable this */
//P_Panic(Lit("Failed to commit new memory block: Overflow of reserved memory"));
(*(volatile int *)0) = 0;
}
void *commit_address = base + arena->committed;
if (!CommitMemory(commit_address, commit_bytes))
{
/* Hard fail on memory allocation failure for now */
/* FIXME: Enable this */
//P_Panic(Lit("Failed to commit new memory block: System may be out of memory"));
(*(volatile int *)0) = 0;
}
arena->committed += commit_bytes;
AddGstat(GSTAT_MEMORY_COMMITTED, commit_bytes);
__proffree(arena);
__profalloc(arena, arena->committed + ArenaHeaderSize);
AsanPoison(commit_address, commit_bytes);
}
ptr = base + aligned_start_pos;
AsanUnpoison(ptr, new_pos - aligned_start_pos);
arena->pos = new_pos;
}
else
{
ptr = base + arena->pos;
}
return ptr;
}
/* Copies the memory from the source arena into the destination arena,
* replacing old contents. Destination arena will be expanded if necessary. */
void CopyArena(Arena *dst, Arena *src)
{
ResetArena(dst);
u64 data_size = src->pos;
u8 *data_src = ArenaBase(src);
u8 *data_dst = PushBytesNoZero(dst, data_size, 1);
CopyBytes(data_dst, data_src, data_size);
}
void ShrinkArena(Arena *arena)
{
/* Not implemented */
Assert(0);
LAX arena;
}
void SetArenaReadonly(Arena *arena)
{
#if RtcIsEnabled
arena->readonly = 1;
#endif
SetMemoryReadonly(arena, arena->committed + ArenaHeaderSize);
}
void SetArenaReadWrite(Arena *arena)
{
SetMemoryReadWrite(arena, arena->committed + ArenaHeaderSize);
#if RtcIsEnabled
arena->readonly = 0;
#endif
}