137 lines
3.0 KiB
C
137 lines
3.0 KiB
C
#include "arena_allocator.h"
|
|
|
|
#include <assert.h>
|
|
#include <string.h> /* memset */
|
|
#include <unistd.h> /* sysconf */
|
|
#include <sys/mman.h> /* madvise */
|
|
|
|
#define MEMORY_ALIGNMENT 2*sizeof(void *)
|
|
|
|
static int power_of_two(int value)
|
|
{
|
|
return (value & (value-1)) == 0;
|
|
}
|
|
|
|
static unsigned long long
|
|
align_address_backward(unsigned long long address,
|
|
unsigned long long alignment)
|
|
{
|
|
unsigned long long mod;
|
|
|
|
assert(power_of_two(alignment));
|
|
|
|
mod = address & (unsigned long long)(alignment-1);
|
|
if(mod != 0)
|
|
address -= mod;
|
|
|
|
return address;
|
|
}
|
|
|
|
static unsigned long long
|
|
align_address_forward(unsigned long long address,
|
|
unsigned long long alignment)
|
|
{
|
|
unsigned long long mod;
|
|
|
|
assert(power_of_two(alignment));
|
|
|
|
mod = address & (unsigned long long)(alignment-1);
|
|
if(mod != 0)
|
|
address += alignment - mod;
|
|
|
|
return address;
|
|
}
|
|
|
|
struct arena arena_init(void *backing_store, unsigned long long size)
|
|
{
|
|
struct arena result;
|
|
|
|
assert(backing_store);
|
|
|
|
memset(&result, 0, sizeof(result));
|
|
|
|
result.size = size;
|
|
result.used = 0;
|
|
result.memory = backing_store;
|
|
return result;
|
|
}
|
|
|
|
void arena_reset(struct arena *arena)
|
|
{
|
|
assert(arena);
|
|
|
|
arena->used = 0;
|
|
}
|
|
|
|
void arena_tidy(struct arena *arena)
|
|
{
|
|
assert(arena);
|
|
|
|
unsigned long long alignment, address, offset;
|
|
|
|
alignment = (unsigned long long)sysconf(_SC_PAGESIZE);
|
|
address = (unsigned long long)(arena->memory + arena->used);
|
|
offset = align_address_forward(address, alignment) - address;
|
|
address += offset;
|
|
|
|
/* TODO: Macos, FreeBSD, and Linux equivalents. */
|
|
madvise((void *)address,
|
|
(size_t)(address - arena->used),
|
|
MADV_DONTNEED);
|
|
}
|
|
|
|
void *arena_alloc(struct arena *arena, unsigned long long size)
|
|
{
|
|
unsigned long long address, offset;
|
|
void *ret_address;
|
|
|
|
assert(arena);
|
|
|
|
ret_address = 0;
|
|
|
|
address = (unsigned long long)(arena->memory + arena->used);
|
|
offset = align_address_forward(address, MEMORY_ALIGNMENT) - address;
|
|
|
|
if(arena->memory + arena->used + offset + size <=
|
|
arena->memory + arena->size)
|
|
{
|
|
ret_address = arena->memory + arena->used + offset;
|
|
memset(ret_address, 0, size);
|
|
arena->used += offset + size;
|
|
}
|
|
|
|
return ret_address;
|
|
}
|
|
#define ARENA_ALLOC(a, t) (t *)arena_alloc(a, sizeof(t))
|
|
|
|
void arena_dealloc(struct arena *arena, unsigned long long size)
|
|
{
|
|
unsigned long long address, offset;
|
|
|
|
assert(arena);
|
|
|
|
address = (unsigned long long)(arena->memory + arena->used - size);
|
|
offset = address - align_address_backward(address, MEMORY_ALIGNMENT);
|
|
|
|
if(address >= (unsigned long long)arena->memory)
|
|
arena->used -= offset + size;
|
|
}
|
|
#define ARENA_DEALLOC(a, t) arena_dealloc(a, sizeof(t))
|
|
|
|
struct arena temp_arena_begin(struct arena *arena)
|
|
{
|
|
struct arena result;
|
|
|
|
assert(arena);
|
|
|
|
result.size = arena->size - arena->used;
|
|
result.used = 0;
|
|
result.memory = arena->memory + arena->used;
|
|
|
|
return result;
|
|
}
|
|
|
|
void temp_arena_end(struct arena *arena)
|
|
{
|
|
}
|