Files
slock/arena_allocator.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)
{
}