152 lines
3.2 KiB
C
152 lines
3.2 KiB
C
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//~ Base arena implementation
|
|
|
|
|
|
internal Arena *
|
|
arena_alloc_()
|
|
{
|
|
U64 reserve_size = g_arena_default_reserve_size;
|
|
U64 commit_size = g_arena_default_commit_size;
|
|
|
|
|
|
// TODO align to page sizes
|
|
|
|
|
|
// Reserve/commit initial block
|
|
void *base = 0;
|
|
if(base == 0) // TODO(anton): can have optional backing buffer
|
|
{
|
|
base = os_reserve(reserve_size);
|
|
os_commit(base, commit_size);
|
|
}
|
|
|
|
// Extract arena header and fill it
|
|
Arena *arena = (Arena *)base;
|
|
arena->current = arena;
|
|
arena->commit_size = commit_size;
|
|
arena->reserve_size = reserve_size;
|
|
arena->base_pos = 0;
|
|
arena->pos = ARENA_HEADER_SIZE;
|
|
arena->commit = commit_size;
|
|
arena->reserve = reserve_size;
|
|
|
|
|
|
return arena;
|
|
}
|
|
|
|
internal void
|
|
arena_release(Arena *arena)
|
|
{
|
|
// Go back in chain and release
|
|
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
|
{
|
|
prev = n->prev;
|
|
os_release(n, n->reserve);
|
|
}
|
|
}
|
|
|
|
internal void *
|
|
arena_push(Arena *arena, U64 size, U64 align)
|
|
{
|
|
Arena *current = arena->current;
|
|
U64 pos_pre = AlignPow2(current->pos, align);
|
|
U64 pos_post = pos_pre + size;
|
|
|
|
// TODO(anton): Add chaining etc. Now we always just put up a new block.
|
|
|
|
|
|
// Commit new pages if needed, that is if the new position of the arena pointer
|
|
// is larger than the current commit adress.
|
|
if(current->commit < pos_post)
|
|
{
|
|
U64 commit_post_aligned = pos_post + current->commit_size - 1;
|
|
commit_post_aligned -= commit_post_aligned % current->commit_size;
|
|
// Now commit_post_aligned is aligned
|
|
U64 commit_post_clamped = ClampTop(commit_post_aligned, current->reserve);
|
|
U64 commit_size = commit_post_clamped - current->commit;
|
|
U8 *commit_ptr = (U8 *)current + current->commit;
|
|
os_commit(commit_ptr, commit_size);
|
|
|
|
current->commit = commit_post_clamped;
|
|
}
|
|
|
|
// Push to current block
|
|
void *result = 0;
|
|
if(current->commit >= pos_post)
|
|
{
|
|
result = (U8 *)current+pos_pre;
|
|
current->pos = pos_post;
|
|
}
|
|
|
|
if(result == 0)
|
|
{
|
|
LOG("FATAL ERROR IN ARENA ALLOC");
|
|
ExitProcess(0);
|
|
}
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
internal U64
|
|
arena_pos(Arena *arena)
|
|
{
|
|
Arena *current = arena->current;
|
|
U64 pos = current->base_pos + current->pos;
|
|
return pos;
|
|
}
|
|
|
|
internal void
|
|
arena_pop_to(Arena *arena, U64 pos)
|
|
{
|
|
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
|
Arena *current = arena->current;
|
|
|
|
|
|
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
|
{
|
|
prev = current->prev;
|
|
os_release(current, current->reserve);
|
|
}
|
|
|
|
arena->current = current;
|
|
U64 new_pos = big_pos - current->base_pos;
|
|
AssertAlways(new_pos <= current->pos);
|
|
current->pos = new_pos;
|
|
}
|
|
|
|
internal void
|
|
arena_clear(Arena *arena)
|
|
{
|
|
arena_pop_to(arena, 0);
|
|
}
|
|
|
|
internal void
|
|
arena_pop(Arena *arena, U64 amt)
|
|
{
|
|
U64 pos_old = arena_pos(arena);
|
|
U64 pos_new = pos_old;
|
|
if(amt < pos_old)
|
|
{
|
|
pos_new = pos_old - amt;
|
|
}
|
|
arena_pop_to(arena, pos_new);
|
|
}
|
|
|
|
//- rjf: temporary arena scopes
|
|
|
|
internal Temp
|
|
temp_begin(Arena *arena)
|
|
{
|
|
U64 pos = arena_pos(arena);
|
|
Temp temp = {arena, pos};
|
|
return temp;
|
|
}
|
|
|
|
internal void
|
|
temp_end(Temp temp)
|
|
{
|
|
arena_pop_to(temp.arena, temp.pos);
|
|
}
|
|
|