11 Commits

7 changed files with 254 additions and 162 deletions

3
.gitignore vendored
View File

@@ -1,4 +1,7 @@
.cache
.vscode
test
test.*
*.dSYM
compile_commands.json
libwapp.so

32
compile
View File

@@ -1,13 +1,39 @@
#!/bin/bash
BUILD_TYPE="debug"
while [[ $# > 0 ]];do
case $1 in
--release)
BUILD_TYPE="release"
shift
;;
*|-*|--*)
echo "Unknown option $1"
exit 1
;;
esac
done
CC=clang
CFLAGS="-Wall -Werror -pedantic "
LIBFLAGS="-fPIC -shared"
INCLUDE="\
$(find src -type d | xargs -I{} echo -n "-I{} ") \
"
SRC="\
$(find src -type f -name *.c | xargs -I{} echo -n "{} ") \
$(find src -type f -name "*.c" | xargs -I{} echo -n "{} ") \
"
CFLAGS="-O3 -shared -fPIC -Wall -Werror -pedantic"
if [[ $BUILD_TYPE == "release" ]]; then
CFLAGS+="-O3"
else
CFLAGS+="-g -fsanitize=address -fsanitize=undefined"
fi
OUT="libwapp.so"
(set -x ; $CC $CFLAGS $INCLUDE $SRC -o $OUT)
(set -x ; $CC $CFLAGS $LIBFLAGS $INCLUDE $SRC -o $OUT)
if [[ -f ./test.c ]]; then
(set -x ; $CC $CFLAGS $INCLUDE $SRC ./test.c -o test)
fi

View File

@@ -13,30 +13,16 @@
#define ARENA_MINIMUM_CAPACITY 1024
typedef struct base_arena BaseArena;
struct base_arena {
struct arena {
u8 *buf;
u8 *offset;
u64 capacity;
BaseArena *prev;
BaseArena *next;
};
struct growing_arena {
BaseArena *active_arena;
u64 count;
u64 initial_capacity;
};
internal bool base_arena_init(BaseArena *arena, u64 capacity);
internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
u64 alignment);
internal void base_arena_clear(BaseArena *arena);
internal void base_arena_destroy(BaseArena *arena);
// PUBLIC API
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) {
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
bool zero_buffer) {
if (!arena || *arena || base_capacity == 0) {
return false;
}
@@ -47,19 +33,21 @@ bool wapp_mem_arena_init(Arena **arena, u64 base_capacity) {
return false;
}
arena_ptr->active_arena = (BaseArena *)calloc(1, sizeof(BaseArena));
if (!(arena_ptr->active_arena)) {
u64 arena_capacity = base_capacity >= ARENA_MINIMUM_CAPACITY
? base_capacity
: ARENA_MINIMUM_CAPACITY;
arena_ptr->buf = (u8 *)wapp_mem_util_alloc(
arena_capacity, WAPP_MEM_ACCESS_READ_WRITE, flags,
zero_buffer ? WAPP_MEM_INIT_INITIALISED : WAPP_MEM_INIT_UNINITIALISED);
if (!(arena_ptr->buf)) {
wapp_mem_arena_destroy(arena);
return false;
}
if (!base_arena_init(arena_ptr->active_arena, base_capacity)) {
wapp_mem_arena_destroy(arena);
return false;
}
arena_ptr->count = 1;
arena_ptr->initial_capacity = base_capacity;
arena_ptr->capacity = arena_capacity;
arena_ptr->offset = arena_ptr->buf;
return true;
}
@@ -69,130 +57,6 @@ void *wapp_mem_arena_alloc(Arena *arena, u64 size) {
}
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment) {
if (!arena || !(arena->active_arena)) {
return NULL;
}
void *output = base_arena_alloc_aligned(arena->active_arena, size, alignment);
if (!output) {
if (arena->active_arena->next) {
arena->active_arena = arena->active_arena->next;
} else {
arena->active_arena->next = (BaseArena *)calloc(1, sizeof(BaseArena));
if (!(arena->active_arena->next)) {
return NULL;
}
if (!base_arena_init(arena->active_arena->next,
arena->initial_capacity)) {
free(arena->active_arena->next);
return NULL;
}
arena->active_arena->next->prev = arena->active_arena;
arena->active_arena = arena->active_arena->next;
++(arena->count);
}
output = base_arena_alloc_aligned(arena->active_arena, size, alignment);
if (!output) {
return NULL;
}
}
memset(output, 0, size);
return output;
}
void wapp_mem_arena_clear(Arena *arena) {
if (!arena) {
return;
}
BaseArena *last_active = NULL;
while (arena->active_arena) {
base_arena_clear(arena->active_arena);
last_active = arena->active_arena;
arena->active_arena = arena->active_arena->prev;
}
arena->active_arena = last_active;
}
void wapp_mem_arena_destroy(Arena **arena) {
if (!arena) {
return;
}
Arena *arena_ptr = *arena;
if (!arena_ptr) {
return;
}
BaseArena *current;
BaseArena *next;
BaseArena *prev;
current = arena_ptr->active_arena->next;
while (current) {
next = current->next;
base_arena_destroy(current);
free(current);
current = next;
}
current = arena_ptr->active_arena->prev;
while (current) {
prev = current->prev;
base_arena_destroy(current);
free(current);
current = prev;
}
base_arena_destroy(arena_ptr->active_arena);
free(arena_ptr->active_arena);
arena_ptr->active_arena = NULL;
arena_ptr->count = 0;
arena_ptr->initial_capacity = 0;
free(*arena);
*arena = NULL;
}
// INTERNAL FUNCTIONS
internal bool base_arena_init(BaseArena *arena, u64 capacity) {
if (!arena || arena->buf || capacity == 0) {
return false;
}
u64 arena_capacity =
capacity >= ARENA_MINIMUM_CAPACITY ? capacity : ARENA_MINIMUM_CAPACITY;
arena->buf = (u8 *)calloc(arena_capacity, sizeof(u8));
if (!(arena->buf)) {
return false;
}
arena->capacity = arena_capacity;
arena->offset = arena->buf;
arena->prev = arena->next = NULL;
return true;
}
internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
u64 alignment) {
if (!arena) {
return NULL;
}
@@ -206,10 +70,12 @@ internal void *base_arena_alloc_aligned(BaseArena *arena, u64 size,
arena->offset = output + size;
memset(output, 0, size);
return (void *)output;
}
internal void base_arena_clear(BaseArena *arena) {
void wapp_mem_arena_clear(Arena *arena) {
if (!arena) {
return;
}
@@ -218,16 +84,19 @@ internal void base_arena_clear(BaseArena *arena) {
arena->offset = arena->buf;
}
internal void base_arena_destroy(BaseArena *arena) {
void wapp_mem_arena_destroy(Arena **arena) {
if (!arena) {
return;
}
if (arena->buf) {
free(arena->buf);
Arena *arena_ptr = *arena;
if (arena_ptr->buf) {
wapp_mem_util_free(arena_ptr->buf, arena_ptr->capacity);
}
arena->buf = arena->offset = NULL;
arena->capacity = 0;
arena->prev = arena->next = NULL;
arena_ptr->buf = arena_ptr->offset = NULL;
arena_ptr->capacity = 0;
free(*arena);
*arena = NULL;
}

View File

@@ -2,15 +2,17 @@
#define MEM_ARENA_H
#include "aliases.h"
#include "mem_utils.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef struct growing_arena Arena;
typedef struct arena Arena;
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity);
bool wapp_mem_arena_init(Arena **arena, u64 base_capacity, MemAllocFlags flags,
bool zero_buffer);
void *wapp_mem_arena_alloc(Arena *arena, u64 size);
void *wapp_mem_arena_alloc_aligned(Arena *arena, u64 size, u64 alignment);
void wapp_mem_arena_clear(Arena *arena);

View File

@@ -1,8 +1,43 @@
#include "mem_utils.h"
#include "aliases.h"
#include "platform.h"
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#if defined(WAPP_PLATFORM_WINDOWS)
#include <Windows.h>
#include <memoryapi.h>
internal const i32 access_types[] = {
[WAPP_MEM_ACCESS_NONE] = PAGE_NOACCESS,
[WAPP_MEM_ACCESS_READ_ONLY] = PAGE_READONLY,
[WAPP_MEM_ACCESS_EXEC_ONLY] = PAGE_EXECUTE,
[WAPP_MEM_ACCESS_READ_WRITE] = PAGE_READWRITE,
[WAPP_MEM_ACCESS_READ_EXEC] = PAGE_EXECUTE_READ,
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PAGE_EXECUTE_READWRITE,
};
internal inline void *alloc_windows(u64 size, MemAccess access,
MemAllocFlags flags);
#elif defined(WAPP_PLATFORM_POSIX)
#include <sys/mman.h>
internal const i32 access_types[] = {
[WAPP_MEM_ACCESS_NONE] = PROT_NONE,
[WAPP_MEM_ACCESS_READ_ONLY] = PROT_READ,
[WAPP_MEM_ACCESS_EXEC_ONLY] = PROT_EXEC,
[WAPP_MEM_ACCESS_READ_WRITE] = PROT_READ | PROT_WRITE,
[WAPP_MEM_ACCESS_READ_EXEC] = PROT_READ | PROT_EXEC,
[WAPP_MEM_ACCESS_READ_WRITE_EXEC] = PROT_READ | PROT_WRITE | PROT_EXEC,
};
internal inline void *alloc_posix(u64 size, MemAccess access,
MemAllocFlags flags);
#else
#error "Unrecognised platform"
#endif
internal bool is_power_of_two(u64 num) { return (num & (num - 1)) == 0; }
@@ -26,3 +61,54 @@ void *wapp_mem_util_align_forward(void *ptr, u64 alignment) {
return (void *)p;
}
void *wapp_mem_util_alloc(u64 size, MemAccess access, MemAllocFlags flags,
MemInitType type) {
#if defined(WAPP_PLATFORM_WINDOWS)
// Ensure memory is committed if it's meant to be initialised
if (type == WAPP_MEM_INIT_INITIALISED) {
flags |= WAPP_MEM_ALLOC_COMMIT;
}
void *output = alloc_windows(size, access, flags);
#elif defined(WAPP_PLATFORM_POSIX)
void *output = alloc_posix(size, access, flags);
#else
return NULL;
#endif
if (type == WAPP_MEM_INIT_INITIALISED) {
memset(output, 0, size);
}
return output;
}
void wapp_mem_util_free(void *ptr, u64 size) {
#if defined(WAPP_PLATFORM_WINDOWS)
VirtualFree(ptr, size, MEM_RELEASE);
#elif defined(WAPP_PLATFORM_POSIX)
munmap(ptr, size);
#endif
}
#ifdef WAPP_PLATFORM_WINDOWS
internal inline void *alloc_windows(u64 size, MemAccess access,
MemAllocFlags flags) {
return VirtualAlloc2(NULL, NULL, (SIZE_T)size, flags, access_types[access]);
}
#endif
#if defined(WAPP_PLATFORM_POSIX)
internal inline void *alloc_posix(u64 size, MemAccess access,
MemAllocFlags flags) {
i32 alloc_flags = flags | MAP_ANON | MAP_PRIVATE;
#if defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU) || \
defined(WAPP_PLATFORM_NET_BSD)
alloc_flags |= MAP_NORESERVE;
#endif
return mmap(NULL, size, access_types[access], alloc_flags, -1, 0);
}
#endif

View File

@@ -2,12 +2,56 @@
#define MEM_UTILS_H
#include "aliases.h"
#include "platform.h"
#if defined(WAPP_PLATFORM_WINDOWS)
#include <Windows.h>
#include <memoryapi.h>
#elif defined(WAPP_PLATFORM_POSIX)
#include <sys/mman.h>
#else
#error "Unrecognised platform"
#endif
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
typedef enum mem_access {
WAPP_MEM_ACCESS_NONE,
WAPP_MEM_ACCESS_READ_ONLY,
WAPP_MEM_ACCESS_EXEC_ONLY,
WAPP_MEM_ACCESS_READ_WRITE,
WAPP_MEM_ACCESS_READ_EXEC,
WAPP_MEM_ACCESS_READ_WRITE_EXEC,
} MemAccess;
typedef enum mem_alloc_flags {
#if defined(WAPP_PLATFORM_WINDOWS)
WAPP_MEM_ALLOC_RESERVE = MEM_RESERVE,
WAPP_MEM_ALLOC_COMMIT = MEM_COMMIT,
#elif defined(WAPP_PLATFORM_LINUX) || defined(WAPP_PLATFORM_GNU)
WAPP_MEM_ALLOC_RESERVE = 0,
WAPP_MEM_ALLOC_COMMIT = MAP_POPULATE,
#elif defined(WAPP_PLATFORM_FREE_BSD)
WAPP_MEM_ALLOC_RESERVE = 0,
WAPP_MEM_ALLOC_COMMIT = MAP_PREFAULT_READ,
#elif defined(WAPP_PLATFORM_BSD) || defined(WAPP_PLATFORM_UNIX) || \
defined(WAPP_PLATFORM_APPLE)
WAPP_MEM_ALLOC_RESERVE = 0,
WAPP_MEM_ALLOC_COMMIT = 0,
#endif
} MemAllocFlags;
typedef enum mem_init_type {
WAPP_MEM_INIT_UNINITIALISED,
WAPP_MEM_INIT_INITIALISED,
} MemInitType;
void *wapp_mem_util_align_forward(void *ptr, u64 alignment);
void *wapp_mem_util_alloc(u64 size, MemAccess access, MemAllocFlags flags,
MemInitType type);
void wapp_mem_util_free(void *ptr, u64 size);
#ifdef __cplusplus
}

62
src/platform/platform.h Normal file
View File

@@ -0,0 +1,62 @@
#ifndef PLATFORM_H
#define PLATFORM_H
#if defined(__ANDROID__)
#define WAPP_PLATFORM_ANDROID
#define WAPP_PLATFORM_POSIX
#elif defined(__FreeBSD__)
#define WAPP_PLATFORM_FREE_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__NetBSD__)
#define WAPP_PLATFORM_NET_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__OpenBSD__)
#define WAPP_PLATFORM_OPEN_BSD
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__DragonFly__)
#define WAPP_PLATFORM_DRAGON_FLY
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__bsdi__)
#define WAPP_PLATFORM_BSD
#define WAPP_PLATFORM_POSIX
#elif defined(__linux__) || defined(linux) || defined(__linux) || \
defined(__gnu_linux__)
#define WAPP_PLATFORM_LINUX
#define WAPP_PLATFORM_POSIX
#elif defined(__GNU__) || defined(__gnu_hurd__)
#define WAPP_PLATFORM_GNU
#define WAPP_PLATFORM_POSIX
#elif defined(__APPLE__) || defined(__MACH__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#define WAPP_PLATFORM_IOS
#define WAPP_PLATFORM_APPLE
#define WAPP_PLATFORM_POSIX
#elif TARGET_OS_MAC
#define WAPP_PLATFORM_MACOS
#define WAPP_PLATFORM_APPLE
#define WAPP_PLATFORM_POSIX
#else
#error "Unrecognised Apple platform"
#endif
#elif defined(_WIN64)
#define WAPP_PLATFORM_WINDOWS64
#define WAPP_PLATFORM_WINDOWS
#elif defined(_WIN32)
#define WAPP_PLATFORM_WINDOWS32
#define WAPP_PLATFORM_WINDOWS
#elif defined(__CYGWIN__)
#define WAPP_PLATFORM_CYGWIN
#define WAPP_PLATFORM_WINDOWS
#elif defined(__unix__) || defined(__unix)
#define WAPP_PLATFORM_UNIX
#define WAPP_PLATFORM_POSIX
#else
#error "Unrecognised platform"
#endif
#endif // !PLATFORM_H