Commit a1f6d03b authored by Nikita Akatiev's avatar Nikita Akatiev
Browse files

Tests rework wip

parent 5358facd
......@@ -33,6 +33,7 @@ if(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()
add_subdirectory(page_routines)
add_subdirectory(src)
option(BUILD_TESTING "Enable tests" ON)
......
add_library(platform_page_routines OBJECT)
target_include_directories(platform_page_routines PUBLIC .)
if (WIN32)
target_sources(platform_page_routines PRIVATE windows.c)
else()
target_sources(platform_page_routines PRIVATE unix.c)
endif()
add_library(page_routines OBJECT page_routines.c)
target_link_libraries(page_routines PUBLIC platform_page_routines)
add_library(page_routines_test OBJECT page_routines_test.c)
target_link_libraries(page_routines_test PUBLIC platform_page_routines)
#include "page_routines.h"
void* map_pages(void const* addr, size_t length, enum page_location location) {
return platform_map_pages(addr, length, location);
}
int unmap_pages(void const* addr, size_t length) {
return platform_unmap_pages(addr, length);
}
int page_size() {
return platform_page_size();
}
#ifndef _PAGE_ROUTINES_H
#define _PAGE_ROUTINES_H
#include <stddef.h>
#define MAP_PAGES_FAILURE ((void*)-1)
enum page_location {
PAGE_FIXED = 0,
PAGE_ANYWHERE
};
/* platform-specific routines for page access */
void* platform_map_pages(void const* addr, size_t length, enum page_location location);
int platform_unmap_pages(void const* addr, size_t length);
int platform_page_size();
/* wrapped calls: for tests, those are used to reimplement or intercept actual API calls */
void* map_pages(void const* addr, size_t length, enum page_location location);
int unmap_pages(void const* addr, size_t length);
int page_size();
#endif
#include "page_routines_test.h"
#include <stdio.h>
static void log_map_pages_call(FILE * output, void const* addr, size_t length, enum page_location location, void* result) {
fputs("addr = ", output);
if (addr) {
fprintf(output, "%p", addr);
} else {
fputs("NULL", output);
}
fprintf(output, ", length = %zu, ", length);
if (location == PAGE_FIXED) {
fputs("location = PAGE_FIXED) -> ", output);
} else if (location == PAGE_ANYWHERE) {
fputs("location = PAGE_ANYWHERE) -> ", output);
} else {
fputs("location = ?) -> ", output);
}
if (result == MAP_PAGES_FAILURE) {
fputs("MAP_PAGES_FAILURE\n", output);
} else if (result) {
fprintf(output, "%p\n", result);
} else {
fputs("NULL\n", output);
}
}
void* map_pages(void const* addr, size_t length, enum page_location location) {
void * result = NULL;
if (current_map_pages_impl) {
/* current_map_pages_impl() may or may not call platform_map_pages() itself */
result = current_map_pages_impl(addr, length, location);
} else {
result = platform_map_pages(addr, length, location);
}
log_map_pages_call(stderr, addr, length, location, result);
return result;
}
int unmap_pages(void const* addr, size_t length) {
return platform_unmap_pages(addr, length);
}
int page_size() {
return platform_page_size();
}
#ifndef _PAGE_ROUTINES_TEST_H
#define _PAGE_ROUTINES_TEST_H
#include "page_routines.h"
#include <stddef.h>
typedef void * (*map_pages_impl)(void const*, size_t, enum page_location);
static map_pages_impl current_map_pages_impl = NULL;
#define DEFINE_MAP_PAGES_IMPL(_name) \
static void * map_pages_impl_##_name(void const* addr, size_t length, enum page_location location)
#define USE_MAP_PAGES_IMPL(_name) current_map_pages_impl = map_pages_impl_##_name
#endif
#include "page_routines.h"
#include <sys/mman.h>
#include <unistd.h>
void* platform_map_pages(void const* addr, size_t length, enum page_location location) {
int additional_flags = (location == PAGE_FIXED) ? MAP_FIXED_NOREPLACE : 0;
void* mapping = mmap( (void*) addr, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | additional_flags, -1, 0 );
return (mapping == MAP_FAILED) ? MAP_PAGES_FAILURE : mapping;
}
int platform_unmap_pages(void const* addr, size_t length) {
return munmap(addr, length);
}
int platform_page_size() {
return getpagesize();
}
#include "page_routines.h"
#include <assert.h>
#include <windows.h>
void* platform_map_pages(void const* addr, size_t length, enum page_location location) {
LPVOID base_address = NULL;
if (location == PAGE_FIXED) {
base_address = (LPVOID) addr; /* use address hint from argument */
}
/* split length (64-bit) into two DWORDs (32-bit) parameters because Win32 */
DWORD len_low = (DWORD)(length & 0xFFFFFFFFL);
DWORD len_high = (DWORD)((length >> 32) & 0xFFFFFFFFL);
HANDLE anon_handle = CreateFileMapping(
/* Anonymous mapping */ INVALID_HANDLE_VALUE,
/* Whatever, security stuff*/ NULL,
PAGE_EXECUTE_READWRITE,
len_high, len_low,
/* Do not give a name to the mapping */ NULL);
if (anon_handle == NULL) {
return MAP_PAGES_FAILURE;
}
void* map = MAP_PAGES_FAILURE;
/* if base_address is not NULL, API call will fail if it cannot create a mapping */
map = MapViewOfFileEx(anon_handle,
FILE_MAP_READ | FILE_MAP_WRITE,
/* offset DWORDs */ 0, 0,
length,
(LPVOID) addr);
CloseHandle(anon_handle);
if (map == NULL) {
return MAP_PAGES_FAILURE;
}
return map;
}
int platform_unmap_pages(void const* addr, size_t length) {
(void) length;
if (UnmapViewOfFile(addr)) {
return 0;
}
return -1;
}
int platform_page_size() {
SYSTEM_INFO si;
GetSystemInfo(&si);
return (int)si.dwPageSize;
}
......@@ -2,6 +2,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL GNU OR CMAKE_C_COMPILER_ID MATCHES Clang)
add_compile_options(-Wall -Werror -Wno-unused -ggdb)
elseif(MSVC)
add_compile_options(/W4 /WX)
add_compile_options(/wd4200) # disable "nonstandard extension used : zero-sized array in struct/union" error in mem_internals.h
endif()
find_program(CLANG_TIDY clang-tidy)
......@@ -17,14 +18,15 @@ if(CLANG_TIDY)
)
endif()
file(GLOB_RECURSE sources CONFIGURE_DEPENDS *.c *.h)
file(GLOB sources CONFIGURE_DEPENDS *.c *.h)
list(FILTER sources EXCLUDE REGEX main.c)
add_library(memalloc STATIC ${sources})
target_include_directories(memalloc PUBLIC .)
target_link_libraries(memalloc PUBLIC platform_page_routines)
if(EXISTS main.c)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
add_executable(memalloc_exe main.c)
target_link_libraries(memalloc_exe PRIVATE memalloc)
target_link_libraries(memalloc_exe PUBLIC memalloc page_routines)
set_target_properties(memalloc_exe PROPERTIES OUTPUT_NAME memalloc)
endif()
#define _DEFAULT_SOURCE
#include <stdio.h>
#include "mem.h"
#include "mem_internals.h"
int main() {
heap_init(REGION_MIN_SIZE);
uint8_t* block = _malloc(64);
_free(block);
printf("Simple malloc test PASSED\n");
uint8_t* blocks[5] = {NULL};
for (size_t i = 0; i < 5; i++) {
blocks[i] = _malloc(64);
}
_free(blocks[1]);
printf("Single free test PASSED\n");
_free(blocks[3]);
_free(blocks[4]);
printf("Multiple free test PASSED\n");
_free(blocks[0]);
_free(blocks[2]);
block = _malloc(4 * REGION_MIN_SIZE);
printf("Region extend test PASSED\n");
_free(block);
return 0;
}
......@@ -3,7 +3,6 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "mem_internals.h"
#include "mem.h"
......@@ -16,10 +15,10 @@ extern inline block_size size_from_capacity( block_capacity cap );
extern inline block_capacity capacity_from_size( block_size sz );
static bool block_is_big_enough( size_t query, struct block_header* block ) { return block->capacity.bytes >= query; }
static size_t pages_count ( size_t mem ) { return mem / getpagesize() + ((mem % getpagesize()) > 0); }
static size_t round_pages ( size_t mem ) { return getpagesize() * pages_count( mem ) ; }
static size_t pages_count ( size_t mem ) { return mem / page_size() + ((mem % page_size()) > 0); }
static size_t round_pages ( size_t mem ) { return page_size() * pages_count( mem ) ; }
static void block_init( void* restrict addr, block_size block_sz, void* restrict next ) {
void block_init( void* restrict addr, block_size block_sz, void* restrict next ) {
*((struct block_header*)addr) = (struct block_header) {
.next = next,
.capacity = capacity_from_size(block_sz),
......@@ -27,19 +26,23 @@ static void block_init( void* restrict addr, block_size block_sz, void* restrict
};
}
static size_t region_actual_size( size_t query ) { return size_max( round_pages( query ), REGION_MIN_SIZE ); }
size_t region_actual_size( size_t query ) { return size_max( round_pages( query ), REGION_MIN_SIZE ); }
extern inline bool region_is_invalid( const struct region* r );
static void* map_pages(void const* addr, size_t length, int additional_flags) {
return mmap( (void*) addr, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | additional_flags , -1, 0 );
}
/* аллоцировать регион памяти и инициализировать его блоком */
static struct region alloc_region ( void const * addr, size_t query ) {
/* ??? */
struct region alloc_region ( void const * addr, size_t query ) {
size_t actual_size = region_actual_size(size_from_capacity((block_capacity){query}).bytes);
void* actual_addr = map_pages(addr, actual_size, PAGE_FIXED);
if (actual_addr == MAP_PAGES_FAILURE)
actual_addr = map_pages(addr, actual_size, PAGE_ANYWHERE);
struct region new_region = {.addr = actual_addr == MAP_PAGES_FAILURE ? NULL : actual_addr,
.size = actual_size,
.extends = actual_addr == addr};
if (!region_is_invalid(&new_region))
block_init(new_region.addr, (block_size){new_region.size}, NULL);
return new_region;
}
static void* block_after( struct block_header const* block ) ;
......@@ -51,16 +54,20 @@ void* heap_init( size_t initial ) {
return region.addr;
}
#define BLOCK_MIN_CAPACITY 24
/* --- Разделение блоков (если найденный свободный блок слишком большой )--- */
static bool block_splittable( struct block_header* restrict block, size_t query) {
return block-> is_free && query + offsetof( struct block_header, contents ) + BLOCK_MIN_CAPACITY <= block->capacity.bytes;
}
static bool split_if_too_big( struct block_header* block, size_t query ) {
/* ??? */
bool split_if_too_big( struct block_header* block, size_t query ) {
if (!block_splittable(block, query))
return false;
void* new_addr = block->contents + query;
block_init(new_addr, (block_size){block->capacity.bytes - query}, block->next);
block->capacity.bytes = query;
block->next = (struct block_header*)(new_addr);
return true;
}
......@@ -79,39 +86,66 @@ static bool mergeable(struct block_header const* restrict fst, struct block_head
return fst->is_free && snd->is_free && blocks_continuous( fst, snd ) ;
}
static bool try_merge_with_next( struct block_header* block ) {
/* ??? */
bool try_merge_with_next( struct block_header* block ) {
struct block_header* next = block->next;
if (next == NULL || !mergeable(block, next))
return false;
block->capacity.bytes += size_from_capacity(next->capacity).bytes;
block->next = next->next;
return true;
}
/* --- ... ecли размера кучи хватает --- */
struct block_search_result {
enum {BSR_FOUND_GOOD_BLOCK, BSR_REACHED_END_NOT_FOUND, BSR_CORRUPTED} type;
struct block_header* block;
};
static struct block_search_result find_good_or_last ( struct block_header* restrict block, size_t sz ) {
/*??? */
struct block_search_result find_good_or_last ( struct block_header* restrict block, size_t sz ) {
while (true) {
if (block->is_free) {
while (try_merge_with_next(block))
;
if (block_is_big_enough(sz, block))
return (struct block_search_result){BSR_FOUND_GOOD_BLOCK, block};
}
if (block->next == NULL)
return (struct block_search_result){BSR_REACHED_END_NOT_FOUND, block};
block = block->next;
}
}
/* Попробовать выделить память в куче начиная с блока `block` не пытаясь расширить кучу
Можно переиспользовать как только кучу расширили. */
static struct block_search_result try_memalloc_existing ( size_t query, struct block_header* block ) {
struct block_search_result try_memalloc_existing ( size_t query, struct block_header* block ) {
struct block_search_result search_result = find_good_or_last(block, query);
if (search_result.type == BSR_FOUND_GOOD_BLOCK) {
split_if_too_big(search_result.block, query);
search_result.block->is_free = false;
}
return search_result;
}
static struct block_header* grow_heap( struct block_header* restrict last, size_t query ) {
/* ??? */
struct block_header* grow_heap( struct block_header* restrict last, size_t query ) {
struct region new_region = alloc_region(last->contents + last->capacity.bytes, query);
if (!region_is_invalid(&new_region) && new_region.extends && last->is_free) {
last->capacity.bytes += new_region.size;
return last;
}
last->next = new_region.addr;
return new_region.addr;
}
/* Реализует основную логику malloc и возвращает заголовок выделенного блока */
static struct block_header* memalloc( size_t query, struct block_header* heap_start) {
struct block_header* memalloc( size_t query, struct block_header* heap_start) {
/* ??? */
query = size_max(query, BLOCK_MIN_CAPACITY);
struct block_search_result search_result = try_memalloc_existing(query, heap_start);
if (search_result.type == BSR_REACHED_END_NOT_FOUND) {
search_result.block = grow_heap(search_result.block, query);
if (search_result.block)
search_result = try_memalloc_existing(query, search_result.block);
}
return search_result.block;
}
......@@ -129,5 +163,6 @@ void _free( void* mem ) {
if (!mem) return ;
struct block_header* header = block_get_header( mem );
header->is_free = true;
/* ??? */
while (try_merge_with_next(header))
;
}
#ifndef _MEM_H_
#define _MEM_H_
#include "../page_routines/page_routines.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#define HEAP_START ((void*)0x04040000)
void* _malloc( size_t query );
......
......@@ -5,6 +5,8 @@
#include <stdbool.h>
#include <stddef.h>
#define BLOCK_MIN_CAPACITY 24
#define REGION_MIN_SIZE (2 * 4096)
struct region { void* addr; size_t size; bool extends; };
......@@ -22,7 +24,22 @@ struct block_header {
uint8_t contents[];
};
struct block_search_result {
enum {BSR_FOUND_GOOD_BLOCK, BSR_REACHED_END_NOT_FOUND, BSR_CORRUPTED} type;
struct block_header* block;
};
inline block_size size_from_capacity( block_capacity cap ) { return (block_size) {cap.bytes + offsetof( struct block_header, contents ) }; }
inline block_capacity capacity_from_size( block_size sz ) { return (block_capacity) {sz.bytes - offsetof( struct block_header, contents ) }; }
size_t region_actual_size( size_t query );
void block_init( void* addr, block_size block_sz, void* next );
struct region alloc_region ( void const * addr, size_t query );
struct block_search_result find_good_or_last ( struct block_header* block, size_t sz );
bool split_if_too_big( struct block_header* block, size_t query );
struct block_header* grow_heap( struct block_header* last, size_t query );
bool try_merge_with_next( struct block_header* block );
struct block_search_result try_memalloc_existing ( size_t query, struct block_header* block );
struct block_header* memalloc( size_t query, struct block_header* heap_start);
#endif
file(GLOB_RECURSE common_sources CONFIGURE_DEPENDS
src/*.c
src/*.h
)
add_library(test_stubs OBJECT ${common_sources})
target_include_directories(test_stubs PUBLIC src)
target_link_libraries(test_stubs PUBLIC memalloc)
file(GLOB_RECURSE test_sources CONFIGURE_DEPENDS
tests/*.c
*.c
)
foreach(test_source IN LISTS test_sources)
......@@ -18,7 +9,7 @@ foreach(test_source IN LISTS test_sources)
list(APPEND test_targets test_${name})
add_executable(test_${name} ${test_source})
target_link_libraries(test_${name} PRIVATE test_stubs)
target_link_libraries(test_${name} PRIVATE memalloc page_routines_test)
add_test(NAME test_${name} COMMAND test_${name})
endforeach()
......
#define TEST_SMART_MMAP
#include "test.h"
#include <assert.h>
#define BUFFER_SIZE 512
// test working with null argument
DEFINE_TEST(null) {
_free(NULL);
......
#define TEST_SMART_MMAP
#include "test.h"
#include <string.h>
static int test_optimistic_case_call_counter = 0;
DEFINE_MAP_PAGES_IMPL(optimistic_case) {
++test_optimistic_case_call_counter;
static int test_optimistic_case_mmap_counter = 0;
DEFINE_MMAP_IMPL(optimistic_case) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
++test_optimistic_case_mmap_counter;
if (test_optimistic_case_mmap_counter == 1) {
assert((flags & MAP_FIXED) || (flags & MAP_FIXED_NOREPLACE));
} else if (test_optimistic_case_mmap_counter == 2) {
assert((~flags & MAP_FIXED) && (~flags & MAP_FIXED_NOREPLACE));
if (test_optimistic_case_call_counter == 1) {
assert(location == PAGE_FIXED);
} else if (test_optimistic_case_call_counter == 2) {
assert(location == PAGE_ANYWHERE);
} else {
assert(false);
}
return mmap(addr, length, prot, flags, fd, offset);
return platform_map_pages(addr, length, location);
}
// test with real HEAP_START and successful mmap MAP_FIXED
DEFINE_TEST(optimistic_case) {
current_mmap_impl = MMAP_IMPL(optimistic_case);
USE_MAP_PAGES_IMPL(optimistic_case);
const struct region region = alloc_region(HEAP_START, 0);
......@@ -32,7 +27,7 @@ DEFINE_TEST(optimistic_case) {
assert(region.size == REGION_MIN_SIZE);
assert(region.extends);
assert(test_optimistic_case_mmap_counter == 1);
assert(test_optimistic_case_call_counter == 1);
struct block_header * block = region.addr;
assert(block->next == NULL);
......@@ -41,27 +36,22 @@ DEFINE_TEST(optimistic_case) {
memset(block->contents, 42, block->capacity.bytes);
munmap(region.addr, region.size);
unmap_pages(region.addr, region.size);
}
static int test_map_fixed_failed_mmap_counter = 0;
DEFINE_MMAP_IMPL(map_fixed_failed) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(map_fixed_failed) {
++test_map_fixed_failed_mmap_counter;
if (test_map_fixed_failed_mmap_counter == 1) {
return MAP_FAILED;
} else {
return mmap(NULL, length, prot, flags, fd, offset);
return MAP_PAGES_FAILURE;
}
return MAP_FAILED;
return platform_map_pages(NULL, length, location);
}
// test with real HEAP_START and failing mmap MAP_FIXED
DEFINE_TEST(map_fixed_failed) {
current_mmap_impl = MMAP_IMPL(map_fixed_failed);
USE_MAP_PAGES_IMPL(map_fixed_failed);
const struct region region = alloc_region(HEAP_START, 0);
......@@ -78,61 +68,55 @@ DEFINE_TEST(map_fixed_failed) {
memset(block->contents, 42, block->capacity.bytes);
munmap(region.addr, region.size);
unmap_pages(region.addr, region.size);
}
static int test_pessimistic_case_mmap_counter = 0;
DEFINE_MMAP_IMPL(pessimistic_case) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(pessimistic_case) {
++test_pessimistic_case_mmap_counter;
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
// test with real HEAP_START and failing mmap MAP_FIXED
DEFINE_TEST(pessimistic_case) {
current_mmap_impl = MMAP_IMPL(pessimistic_case);
USE_MAP_PAGES_IMPL(pessimistic_case);
const struct region region = alloc_region(HEAP_START, 0);
assert(region.addr == NULL);
assert(test_pessimistic_case_mmap_counter == 2);
}
DEFINE_MMAP_IMPL(query_is_small) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(query_is_small) {
assert(length == REGION_MIN_SIZE);
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
// test with query = 0
DEFINE_TEST(query_is_zero) {
current_mmap_impl = MMAP_IMPL(query_is_small);
USE_MAP_PAGES_IMPL(query_is_small);
alloc_region(HEAP_START, 0);
}
// test with query > 0 and query < REGION_MIN_SIZE
DEFINE_TEST(query_is_small) {
current_mmap_impl = MMAP_IMPL(query_is_small);
USE_MAP_PAGES_IMPL(query_is_small);
alloc_region(HEAP_START, 42);
}
DEFINE_MMAP_IMPL(query_is_min_region_size) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
assert(length == (size_t) (REGION_MIN_SIZE + getpagesize()));
return mmap(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(query_is_min_region_size) {
assert(length == (size_t) (REGION_MIN_SIZE + page_size()));
return platform_map_pages(addr, length, location);
}
// test with query == REGION_MIN_SIZE (to check is block header size counted in mmap length)
DEFINE_TEST(query_is_min_region_size) {
current_mmap_impl = MMAP_IMPL(query_is_min_region_size);
USE_MAP_PAGES_IMPL(query_is_min_region_size);
const struct region region = alloc_region(HEAP_START, REGION_MIN_SIZE);
assert(region.addr == HEAP_START);
assert(region.size == (size_t) (REGION_MIN_SIZE + getpagesize()));
assert(region.size == (size_t) (REGION_MIN_SIZE + page_size()));
assert(region.extends);
struct block_header * block = region.addr;
......@@ -142,7 +126,7 @@ DEFINE_TEST(query_is_min_region_size) {
memset(block->contents, 42, block->capacity.bytes);
munmap(region.addr, region.size);
unmap_pages(region.addr, region.size);
}
DEFINE_TEST_GROUP(query) {
......
#define TEST_SMART_MMAP
#include "test.h"
#include <assert.h>
#define BUFFER_SIZE 1024
// +------------+
// | good block |-->NULL
// +------------+
......
#define TEST_SMART_MMAP
#include "test.h"
#include <string.h>
......@@ -11,20 +9,17 @@
static uint8_t buffer[BUFFER_SIZE] = { 0 };
static int test_mmap_counter = 0;
DEFINE_MMAP_IMPL(mmap_failed) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(mmap_pages_failed) {
assert(addr == buffer + BLOCK_SIZE);
assert(length == REGION_MIN_SIZE);
++test_mmap_counter;
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
// test when mmap failed -> no changes in heap, returns NULL
DEFINE_TEST(mmap_failed) {
current_mmap_impl = MMAP_IMPL(mmap_failed);
USE_MAP_PAGES_IMPL(mmap_pages_failed);
struct block_header * const block = (void*) buffer;
block_init(block, (block_size) { .bytes = BLOCK_SIZE }, NULL);
......@@ -40,15 +35,13 @@ DEFINE_TEST(mmap_failed) {
assert(block->is_free == true);
}
DEFINE_MMAP_IMPL(mmap_fixed_failed) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(mmap_fixed_failed) {
assert(length == REGION_MIN_SIZE);
++test_mmap_counter;
if ((flags & MAP_FIXED) || (flags & MAP_FIXED_NOREPLACE)) {
if (location == PAGE_FIXED) {
assert(addr == buffer + BLOCK_SIZE / 2);
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
return buffer + BLOCK_SIZE;
......@@ -56,7 +49,7 @@ DEFINE_MMAP_IMPL(mmap_fixed_failed) {
// test when mmap fixed failed -> only chain last with new, returns new region addr
DEFINE_TEST(mmap_fixed_failed) {
current_mmap_impl = MMAP_IMPL(mmap_fixed_failed);
USE_MAP_PAGES_IMPL(mmap_fixed_failed);
struct block_header * const block = (void*) buffer;
block_init(block, (block_size) { .bytes = BLOCK_SIZE / 2 }, NULL);
......@@ -76,12 +69,10 @@ DEFINE_TEST(mmap_fixed_failed) {
assert(result->is_free == true);
}
DEFINE_MMAP_IMPL(mmap_success) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(mmap_success) {
assert(addr == buffer + BLOCK_SIZE);
assert(length == REGION_MIN_SIZE);
assert((flags & MAP_FIXED) || (flags & MAP_FIXED_NOREPLACE));
assert(location == PAGE_FIXED);
++test_mmap_counter;
return buffer + BLOCK_SIZE;
......@@ -89,7 +80,7 @@ DEFINE_MMAP_IMPL(mmap_success) {
// test when mmap success and last is dirty -> only chain last with new, returns new region addr
DEFINE_TEST(mmap_success_last_dirty) {
current_mmap_impl = MMAP_IMPL(mmap_success);
USE_MAP_PAGES_IMPL(mmap_success);
struct block_header * const block = (void*) buffer;
block_init(block, (block_size) { .bytes = BLOCK_SIZE }, NULL);
......@@ -112,7 +103,7 @@ DEFINE_TEST(mmap_success_last_dirty) {
// test when mmap success and last is free -> merge last with new, returns old last
DEFINE_TEST(mmap_success_last_free) {
current_mmap_impl = MMAP_IMPL(mmap_success);
USE_MAP_PAGES_IMPL(mmap_success);
struct block_header * const block = (void*) buffer;
block_init(block, (block_size) { .bytes = BLOCK_SIZE }, NULL);
......
......@@ -9,16 +9,15 @@ static const size_t corner_cases[] = { 0, 10, 24, 24 + offsetof(struct block_hea
static size_t test_length = 0;
static int mmap_counter = 0;
DEFINE_MMAP_IMPL(fail) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(fail) {
assert(addr == HEAP_START && length == region_actual_size(test_length + offsetof(struct block_header, contents)));
++mmap_counter;
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
// test when mmap failed
DEFINE_TEST(fail) {
current_mmap_impl = MMAP_IMPL(fail);
USE_MAP_PAGES_IMPL(fail);
for (size_t i = 0; i < sizeof(corner_cases) / sizeof(*corner_cases); ++i) {
test_length = corner_cases[i];
......@@ -33,16 +32,15 @@ DEFINE_TEST(fail) {
static void * mmap_result = NULL;
DEFINE_MMAP_IMPL(success) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(success) {
assert(addr == HEAP_START && length == region_actual_size(test_length + offsetof(struct block_header, contents)));
++mmap_counter;
return (mmap_result = mmap(addr, length, prot, flags, fd, offset));
return (mmap_result = platform_map_pages(addr, length, location));
}
// test when mmap success
DEFINE_TEST(success) {
current_mmap_impl = MMAP_IMPL(success);
USE_MAP_PAGES_IMPL(success);
for (size_t i = 0; i < sizeof(corner_cases) / sizeof(*corner_cases); ++i) {
test_length = corner_cases[i];
......@@ -55,7 +53,7 @@ DEFINE_TEST(success) {
assert(result == mmap_result);
assert(mmap_counter == 1);
munmap(result, region_actual_size(test_length + offsetof(struct block_header, contents)));
unmap_pages(result, region_actual_size(test_length + offsetof(struct block_header, contents)));
}
}
......
#define TEST_SMART_MMAP
#include "test.h"
#include <assert.h>
#define BUFFER_SIZE 1024
// test memalloc existing with big query
// +-------------+ +-------------+ +-+ +-+ +-------------+
// | small block |-->| dirty block |-->| |->...small blocks...->| |-->| dirty block |
......@@ -116,14 +111,12 @@ static uint8_t buffer[BUFFER_SIZE] = { 0 };
static int test_mmap_counter = 0;
static size_t mmap_length = REGION_MIN_SIZE * 2;
DEFINE_MMAP_IMPL(mmap_failed) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(mmap_failed) {
assert(addr == buffer + BUFFER_SIZE);
assert(length == mmap_length);
++test_mmap_counter;
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
// test grow heap fail with big query (bigger than 2 pages)
......@@ -131,7 +124,7 @@ DEFINE_MMAP_IMPL(mmap_failed) {
// | small block |-->| dirty block |-->| |->...small blocks...->| |-->| dirty block |-->| small block |
// +-------------+ +-------------+ +-+ +-+ +-------------+ +-------------+
DEFINE_TEST(grow_heap_fail_big_query) {
current_mmap_impl = MMAP_IMPL(mmap_failed);
USE_MAP_PAGES_IMPL(mmap_failed);
struct block_header * const block1 = (void*) (buffer + 0 * BUFFER_SIZE / 8);
struct block_header * const block2 = (void*) (buffer + 1 * BUFFER_SIZE / 8);
......@@ -154,7 +147,7 @@ DEFINE_TEST(grow_heap_fail_big_query) {
block2->is_free = false;
block7->is_free = false;
mmap_length = REGION_MIN_SIZE + getpagesize();
mmap_length = REGION_MIN_SIZE + page_size();
test_mmap_counter = 0;
struct block_header * const result = memalloc(REGION_MIN_SIZE, block1);
......@@ -188,7 +181,7 @@ DEFINE_TEST(grow_heap_fail_big_query) {
// | dirty block |
// +-------------+
DEFINE_TEST(grow_heap_fail_small_query) {
current_mmap_impl = MMAP_IMPL(mmap_failed);
USE_MAP_PAGES_IMPL(mmap_failed);
struct block_header * const block = (void*) buffer;
block_init(block, (block_size) { .bytes = BUFFER_SIZE }, NULL);
......@@ -209,15 +202,13 @@ DEFINE_TEST(grow_heap_fail_small_query) {
static uint8_t mmap_buffer[REGION_MIN_SIZE] = { 0 };
DEFINE_MMAP_IMPL(mmap_fixed_failed) {
base_mmap_checks(addr, length, prot, flags, fd, offset);
DEFINE_MAP_PAGES_IMPL(mmap_fixed_failed) {
assert(length == REGION_MIN_SIZE);
++test_mmap_counter;
if (test_mmap_counter == 1) {
assert(addr == buffer + BUFFER_SIZE);
return MAP_FAILED;
return MAP_PAGES_FAILURE;
}
return mmap_buffer;
......@@ -228,7 +219,7 @@ DEFINE_MMAP_IMPL(mmap_fixed_failed) {
// | small block |-->| dirty block |-->| |->...small blocks...->| |-->| dirty block |-->| small block |
// +-------------+ +-------------+ +-+ +-+ +-------------+ +-------------+
DEFINE_TEST(grow_heap_success_big_query) {
current_mmap_impl = MMAP_IMPL(mmap_fixed_failed);
USE_MAP_PAGES_IMPL(mmap_fixed_failed);
struct block_header * const block1 = (void*) (buffer + 0 * BUFFER_SIZE / 8);
struct block_header * const block2 = (void*) (buffer + 1 * BUFFER_SIZE / 8);
......@@ -293,7 +284,7 @@ DEFINE_TEST(grow_heap_success_big_query) {
// | dirty block |
// +-------------+
DEFINE_TEST(grow_heap_success_small_query) {
current_mmap_impl = MMAP_IMPL(mmap_fixed_failed);
USE_MAP_PAGES_IMPL(mmap_fixed_failed);
struct block_header * const block = (void*) buffer;
block_init(block, (block_size) { .bytes = BUFFER_SIZE }, NULL);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment