diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/arena.c | 135 | ||||
-rw-r--r-- | test/test-internal.h | 20 |
2 files changed, 155 insertions, 0 deletions
diff --git a/test/arena.c b/test/arena.c new file mode 100644 index 0000000..58b3076 --- /dev/null +++ b/test/arena.c @@ -0,0 +1,135 @@ +#include <sys/mman.h> + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> + +#include "alloc.h" +#include "test-internal.h" + +#define lengthof(xs) (sizeof(xs) / sizeof(*(xs))) + +static void make_and_free(void), + make_and_resize(void), + free_empty_arena(void), + make_snapshot(void); + +int +main(void) +{ + make_and_free(); + make_and_resize(); + free_empty_arena(); + make_snapshot(); + return rv; +} + +void +make_and_free(void) +{ + arena_t a = NULL; + int *xs = arena_new(&a, int, 69); + + for (size_t i = 0; i < 69; i++) + xs[i] = i; + + arena_free(&a); +} + +void +make_and_resize(void) +{ + arena_t a = NULL; + size_t *xs = arena_new(&a, size_t, 100); + for (size_t i = 0; i < 100; i++) + xs[i] = i; + + static size_t ranges[][2] = { + { 100, 1000}, + { 1000, 10000}, + {10000, 100000}, + }; + + for (size_t i = 0; i < lengthof(ranges); i++) { + size_t lo = ranges[i][0]; + size_t hi = ranges[i][1]; + + xs = arena_grow(&a, xs, size_t, lo, hi); + for (size_t j = lo; j < hi; j++) + xs[j] = j; + } + + for (size_t i = 0; i < ranges[lengthof(ranges) - 1][1]; i++) + oryx_assert(xs[i] == i); + +cleanup: + arena_free(&a); +} + +void +free_empty_arena(void) +{ + arena_free(&(arena_t){0}); +} + +void +make_snapshot(void) +{ + arena_t a = NULL; + + char *p1, *p2, *p3; + snapshot_t s1, s2, s3; + + /* The arena by default is backed my mmap(), and makes pages of size + _ARENA_DFLT_CAP or larger. This means we can test to see if the + arena snapshotting is properly implemented by: + + 1. Creating allocations of the blocksize. This ensures each + allocation is on its own page as allocated by mmap(2). + 2. Creating a snapshot before each allocation. + 3. Restoring snapshots and checking to see which pages are still + valid via mincore() which errors with ENOMEM if the page isn’t + mapped. + + Technically mincore() is non-standard… but it exists on all major + BSDs as well as Linux and Darwin. */ + + s1 = arena_snapshot_create(a); p1 = arena_new(&a, char, _ARENA_DFLT_CAP); + s2 = arena_snapshot_create(a); p2 = arena_new(&a, char, _ARENA_DFLT_CAP); + s3 = arena_snapshot_create(a); p3 = arena_new(&a, char, _ARENA_DFLT_CAP); + + unsigned char *vec = NULL; + size_t pagesz = (size_t)sysconf(_SC_PAGESIZE); + oryx_assert(pagesz != (size_t)-1); + + /* Vector size documented in mincore(2) */ + vec = malloc((_ARENA_DFLT_CAP + pagesz - 1) / pagesz); + oryx_assert(vec != NULL); + + errno = 0; mincore(p1, _ARENA_DFLT_CAP, vec); oryx_assert(errno == 0); + errno = 0; mincore(p2, _ARENA_DFLT_CAP, vec); oryx_assert(errno == 0); + errno = 0; mincore(p3, _ARENA_DFLT_CAP, vec); oryx_assert(errno == 0); + + arena_snapshot_restore(&a, s3); + errno = 0; mincore(p1, _ARENA_DFLT_CAP, vec); oryx_assert(errno == 0); + errno = 0; mincore(p2, _ARENA_DFLT_CAP, vec); oryx_assert(errno == 0); + errno = 0; mincore(p3, _ARENA_DFLT_CAP, vec); oryx_assert(errno == ENOMEM); + oryx_assert(a != NULL); + + arena_snapshot_restore(&a, s2); + errno = 0; mincore(p1, _ARENA_DFLT_CAP, vec); oryx_assert(errno == 0); + errno = 0; mincore(p2, _ARENA_DFLT_CAP, vec); oryx_assert(errno == ENOMEM); + errno = 0; mincore(p3, _ARENA_DFLT_CAP, vec); oryx_assert(errno == ENOMEM); + oryx_assert(a != NULL); + + arena_snapshot_restore(&a, s1); + errno = 0; mincore(p1, _ARENA_DFLT_CAP, vec); oryx_assert(errno == ENOMEM); + errno = 0; mincore(p2, _ARENA_DFLT_CAP, vec); oryx_assert(errno == ENOMEM); + errno = 0; mincore(p3, _ARENA_DFLT_CAP, vec); oryx_assert(errno == ENOMEM); + oryx_assert(a == NULL); + +cleanup: + free(vec); + arena_free(&a); +} diff --git a/test/test-internal.h b/test/test-internal.h new file mode 100644 index 0000000..78f5e7b --- /dev/null +++ b/test/test-internal.h @@ -0,0 +1,20 @@ +#ifndef ORYX_TEST_INTERNAL_H +#define ORYX_TEST_INTERNAL_H + +#include <stdio.h> +#include <stdlib.h> + +static int rv; + +#define oryx_assert(expr) \ + do { \ + if (!(expr)) { \ + fprintf(stderr, "%s:%d: Test ‘%s’ failed\n", __FILE__, __LINE__, \ + __func__); \ + fprintf(stderr, "\tFailing expression: ‘%s’\n", #expr); \ + rv = EXIT_FAILURE; \ + goto cleanup; \ + } \ + } while (0) + +#endif /* !ORYX_TEST_INTERNAL_H */ |