Rewrite everything
This commit is contained in:
4
Makefile
4
Makefile
@@ -6,8 +6,8 @@ BUILD_DIR := build
|
|||||||
BIN_DIR := lib
|
BIN_DIR := lib
|
||||||
TEST_DIR := test
|
TEST_DIR := test
|
||||||
|
|
||||||
OBJS := $(BUILD_DIR)/arena.o $(BUILD_DIR)/alloc_backend.o
|
OBJS := $(BUILD_DIR)/arena.o
|
||||||
FPIC_OBJS := $(BUILD_DIR)/fpic/arena.o $(BUILD_DIR)/fpic/alloc_backend.o
|
FPIC_OBJS := $(BUILD_DIR)/fpic/arena.o
|
||||||
|
|
||||||
static : $(BIN_DIR)/libarena.a
|
static : $(BIN_DIR)/libarena.a
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
#ifndef ALLOC_BACKEND_H
|
|
||||||
#define ALLOC_BACKEND_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
void* call_alloc_backend(size_t size);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -4,16 +4,17 @@
|
|||||||
|
|
||||||
#include <stddef.h> // ptrdiff_t
|
#include <stddef.h> // ptrdiff_t
|
||||||
|
|
||||||
|
typedef unsigned char byte_t;
|
||||||
|
|
||||||
typedef struct arena {
|
typedef struct arena {
|
||||||
void *begin,
|
size_t next, prev, cap;
|
||||||
*next,
|
void* data;
|
||||||
*prev;
|
|
||||||
size_t cap;
|
|
||||||
} __attribute__((aligned(sizeof(void*)))) arena_t;
|
} __attribute__((aligned(sizeof(void*)))) arena_t;
|
||||||
|
|
||||||
arena_t* arena_new();
|
arena_t arena_new();
|
||||||
void arena_reset(arena_t* a);
|
void arena_reset(arena_t* a);
|
||||||
void* arena_alloc(arena_t* a, size_t len);
|
void* arena_alloc(arena_t* a, size_t len);
|
||||||
|
void* arena_calloc(arena_t* a, size_t nmemb, size_t size);
|
||||||
void* arena_realloc_tail(arena_t* a, size_t len);
|
void* arena_realloc_tail(arena_t* a, size_t len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
#include "alloc_backend.h"
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Separate function to make switching
|
|
||||||
* allocation backend easier
|
|
||||||
*
|
|
||||||
* must take size_t size as an argument
|
|
||||||
* must return NULL on failure
|
|
||||||
*/
|
|
||||||
void* call_alloc_backend(size_t size)
|
|
||||||
{
|
|
||||||
void* p = mmap(
|
|
||||||
NULL,
|
|
||||||
size,
|
|
||||||
PROT_READ | PROT_WRITE,
|
|
||||||
MAP_ANONYMOUS | MAP_PRIVATE,
|
|
||||||
-1, /* man mmap(2): "[...], some implementations require fd to be
|
|
||||||
-1 if MAP_ANONYMOUS is specified [...]" */
|
|
||||||
0);
|
|
||||||
|
|
||||||
if (p == MAP_FAILED)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
98
src/arena.c
98
src/arena.c
@@ -1,77 +1,79 @@
|
|||||||
|
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "alloc_backend.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define ARENA_SIZE ((size_t)(128 * sysconf(_SC_PAGE_SIZE)))
|
#include <stdio.h>
|
||||||
|
|
||||||
typedef unsigned char byte;
|
// (sizeof(intptr_t) isn't guaranteed to be the machine word size but on most
|
||||||
|
// compilers it is)
|
||||||
|
#define WORD_SIZE (sizeof(intptr_t))
|
||||||
|
|
||||||
/*
|
#define ARENA_SIZE ((size_t)(1 * sysconf(_SC_PAGE_SIZE)))
|
||||||
* Allocates and returns new arena
|
|
||||||
*/
|
struct arena arena_new()
|
||||||
struct arena* arena_new()
|
|
||||||
{
|
{
|
||||||
size_t size = ARENA_SIZE;
|
arena_t a = {
|
||||||
|
.next = 0,
|
||||||
|
.prev = 0,
|
||||||
|
.cap = ARENA_SIZE,
|
||||||
|
.data = malloc(ARENA_SIZE)
|
||||||
|
};
|
||||||
|
|
||||||
byte* p = call_alloc_backend(size);
|
if (a.data == NULL)
|
||||||
|
exit(errno);
|
||||||
if (p == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
arena_t* a = (arena_t*)p;
|
|
||||||
|
|
||||||
void* beg = p + sizeof(struct arena);
|
|
||||||
a->begin = beg;
|
|
||||||
a->next = beg;
|
|
||||||
a->prev = beg;
|
|
||||||
a->cap = size - sizeof(struct arena);
|
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void _arena_realloc_or_panic(arena_t* a, size_t len)
|
||||||
* Frees all memory in arena
|
|
||||||
*/
|
|
||||||
void arena_reset(struct arena* a)
|
|
||||||
{
|
{
|
||||||
a->next = a->begin;
|
// TODO: gracefully recover.
|
||||||
a->prev = a->begin;
|
// although unlikely to be recoverable in most use cases
|
||||||
|
a->data = realloc(a->data, len);
|
||||||
|
|
||||||
|
if (a->data == NULL)
|
||||||
|
exit(errno);
|
||||||
|
|
||||||
|
a->cap = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arena_reset(struct arena* a)
|
||||||
|
{
|
||||||
|
a->next = 0;
|
||||||
|
a->prev = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate new memory using arena
|
|
||||||
*/
|
|
||||||
void* arena_alloc(struct arena* a, size_t len)
|
void* arena_alloc(struct arena* a, size_t len)
|
||||||
{
|
{
|
||||||
void* p = a->next;
|
// align len to machine word size
|
||||||
|
len = (len + WORD_SIZE - 1) & ~(WORD_SIZE - 1);
|
||||||
|
fprintf(stderr, "allocating %zu bytes\n", len);
|
||||||
|
|
||||||
if ((byte*)p + len > (byte*)(a->begin) + a->cap) {
|
a->prev = a->next;
|
||||||
errno = ENOMEM;
|
a->next += len;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
a->next = (byte*)(a->next) + len;
|
if (a->next > a->cap)
|
||||||
a->prev = p;
|
_arena_realloc_or_panic(a, a->cap * 2);
|
||||||
|
|
||||||
|
|
||||||
|
return (byte_t*)(a->data) + a->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* arena_calloc(struct arena* a, size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void* p = arena_alloc(a, nmemb * size);
|
||||||
|
memset((byte_t*)(a->data) + a->prev, 0, size);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Reallocate last block in arena
|
|
||||||
*/
|
|
||||||
void* arena_realloc_tail(struct arena* a, size_t len)
|
void* arena_realloc_tail(struct arena* a, size_t len)
|
||||||
{
|
{
|
||||||
void* p = a->prev;
|
a->next = a->prev;
|
||||||
|
|
||||||
if ((byte*)p + len > (byte*)(a->begin) + a->cap) {
|
return arena_alloc(a, len);
|
||||||
errno = ENOMEM;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
a->next = (byte*)p + len;
|
|
||||||
|
|
||||||
return a->prev;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,25 +8,23 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static struct arena* default_arena = NULL;
|
static struct arena default_arena = { 0 };
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
default_arena = arena_new();
|
default_arena = arena_new();
|
||||||
|
|
||||||
if (default_arena == NULL) {
|
printf("\nAttempt to do allocations of 1 byte, cap is %zu, ", default_arena.cap);
|
||||||
err(errno, "failed to allocate arena");
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nAttempt to do `arena->cap` allocations of 1 byte");
|
size_t i;
|
||||||
|
for (i = 0; default_arena.next < default_arena.cap; i++) {
|
||||||
for (size_t i = 0; i < default_arena->cap; i++) {
|
char* c = arena_alloc(&default_arena, 1);
|
||||||
char* c = arena_alloc(default_arena, 1);
|
|
||||||
*c = i & 0xff;
|
*c = i & 0xff;
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
err(EXIT_FAILURE, "failed to allocate memory");
|
err(EXIT_FAILURE, "failed to allocate memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
printf("did %zu allocations", i);
|
||||||
|
|
||||||
printf("\n OK");
|
printf("\n OK");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user