From 726c2315617a7f6c53607922727b30a1453515f9 Mon Sep 17 00:00:00 2001 From: Eric-Paul Ickhorn Date: Tue, 20 Feb 2024 07:35:53 +0100 Subject: [PATCH] Added shadow tag registry --- action.bash | 28 ++- core/build-config/tests.txt | 1 + core/inc-c/context.h | 13 ++ core/inc-c/entity.h | 24 +++ core/inc-c/shadow-tag.h | 117 +++++++++++ core/src-c/shadow-tag.c | 187 ++++++++++++++++++ .../internal/shadow-tag/include_paths.txt | 1 + core/tests/internal/shadow-tag/main.c | 80 ++++++++ 8 files changed, 446 insertions(+), 5 deletions(-) create mode 100644 core/inc-c/context.h create mode 100644 core/inc-c/entity.h create mode 100644 core/inc-c/shadow-tag.h create mode 100644 core/src-c/shadow-tag.c create mode 100644 core/tests/internal/shadow-tag/include_paths.txt create mode 100644 core/tests/internal/shadow-tag/main.c diff --git a/action.bash b/action.bash index 7b890f2..0f2fd18 100755 --- a/action.bash +++ b/action.bash @@ -11,6 +11,12 @@ RELEASE_CC_OPTIONS="-O3 -Wall" MAIN_OBJECTS_FOLDER="$REPOSITORY_FOLDER/.build/objects" CONFIG_FILE_INCLUDE_PATHS="build-config/include_paths.txt" +DEFAULT_TEST_LINKAGE_PATHS=".build/maintree-core.a .build/librr-core.a .build/librr-platform.a" +DEFAULT_TEST_INCLUDE_STATEMENTS=" +-I .build/depends/libRR/Core/core/exports +-I .build/depends/libRR/Core/platform/exports +" + function clone_dependencies { echo "================ Cloning Dependencies! ================" mkdir -p .build/depends/libRR @@ -116,10 +122,10 @@ function compile_module_c_sources { cd $REPOSITORY_FOLDER } -function get_linkage_path_configuration() { +function get_test_linkage_path_configuration() { TEST_PATH=$1 - LINKAGE_PATHS=$DEFAULT_LINKAGE_PATHS + LINKAGE_PATHS=$DEFAULT_TEST_LINKAGE_PATHS if [[ -f "$TEST_PATH/linkage_paths.txt" ]] then for LINKAGE_ITEM in $(cat "$TEST_PATH/linkage_paths.txt") @@ -129,6 +135,17 @@ function get_linkage_path_configuration() { fi } +function get_test_include_path_configuration() { + INCLUDE_PATHS=$DEFAULT_TEST_INCLUDE_STATEMENTS + if [[ -f "$TEST_PATH/include_paths.txt" ]] + then + for INCLUDE_ITEM in $(cat "$TEST_PATH/include_paths.txt") + do + INCLUDE_PATHS="$INCLUDE_PATHS -I $REPOSITORY_FOLDER/$INCLUDE_ITEM" + done + fi +} + function compile_single_test() { TEST_PATH=$1 TEST_NAME=$(basename $TEST_PATH) @@ -137,9 +154,10 @@ function compile_single_test() { # TODO: As a small improvement, the tests could be able to have multiple sub-folders for sources. - get_include_path_configuration $TEST_PATH - get_linkage_path_configuration $TEST_PATH - gcc $CC_OPTIONS -o $TEST_PATH/$TEST_NAME.elf $TEST_PATH/*.c $LINKAGE_PATHS $INCLUDE_STATEMENTS + get_test_include_path_configuration $TEST_PATH + get_test_linkage_path_configuration $TEST_PATH + echo $INCLUDE_PATHS + gcc $CC_OPTIONS -o $TEST_PATH/$TEST_NAME.elf $TEST_PATH/*.c $LINKAGE_PATHS $INCLUDE_PATHS } function compile_all_tests_of_module() { diff --git a/core/build-config/tests.txt b/core/build-config/tests.txt index e69de29..4800e89 100644 --- a/core/build-config/tests.txt +++ b/core/build-config/tests.txt @@ -0,0 +1 @@ +tests/internal/shadow-tag \ No newline at end of file diff --git a/core/inc-c/context.h b/core/inc-c/context.h new file mode 100644 index 0000000..8964957 --- /dev/null +++ b/core/inc-c/context.h @@ -0,0 +1,13 @@ + +#ifndef MT_CONTEXT_H +#define MT_CONTEXT_H + +#include +#include + +typedef struct MtContext +{ + MtShadowTagSystem shadow_tag_system; +} MtContext; + +#endif // MT_CONTEXT_H diff --git a/core/inc-c/entity.h b/core/inc-c/entity.h new file mode 100644 index 0000000..895e7a3 --- /dev/null +++ b/core/inc-c/entity.h @@ -0,0 +1,24 @@ + +#ifndef MT_ENTITY_H +#define MT_ENTITY_H + +#include + +typedef struct MtEntity MtEntity; + +/// @brief: An MtEntity is a frontend descriptor which stands in +/// the place of internal data without the need to reference +/// actual internal data. +struct MtEntity +{ + /// @brief: The context which this MtEntity belongs to. This is + /// also the context which is referenced each time a function + /// uses the entity and needs to find its shadow. + void *context; + + /// @brief: The identifier of the background structure "shadow". + /// This is used for resolving this entity to its actual data. + u32_t shadow_id; +}; + +#endif // MT_ENTITY_H diff --git a/core/inc-c/shadow-tag.h b/core/inc-c/shadow-tag.h new file mode 100644 index 0000000..d38f319 --- /dev/null +++ b/core/inc-c/shadow-tag.h @@ -0,0 +1,117 @@ + +#ifndef MT_SHADOW_TAG_H +#define MT_SHADOW_TAG_H + +#include +#include +#include + +typedef struct MtShadowTag MtShadowTag; +typedef struct MtShadowTagPool MtShadowTagPool; +typedef struct MtShadowTagName MtShadowTagName; +typedef struct MtShadowTagNameArena MtShadowTagNameArena; +typedef struct MtShadowTagNameRegistry MtShadowTagNameRegistry; +typedef struct MtShadowTagSystem MtShadowTagSystem; + +typedef enum +{ + MT_SHADOW_TAG_INTEGER, + MT_SHADOW_TAG_BOOLEAN, + MT_SHADOW_TAG_DECIMAL, + MT_SHADOW_TAG_STRING, + MT_SHADOW_TAG_RAW_POINTER, + MT_SHADOW_TAG_VECTOR_2, + MT_SHADOW_TAG_VECTOR_3, + MT_SHADOW_TAG_VECTOR_4, + MT_SHADOW_TAG_SUB_ENTITY, + MT_SHADOW_TAG_RESOURCE + +} MtShadowTagType; + +struct MtShadowTag +{ + MtShadowTagPool *pool; + MtShadowTag *next; + + MtShadowTagType type; + u32_t name_identifier; + union MtShadowTagData + { + bool_t boolean; + i64_t integer; + f64_t decimal; + char *string; + void *raw_pointer; + rr_vec2f_s vec2f; + rr_vec3f_s vec3f; + rr_vec4f_s vec4f; + MtEntity entity; + } data; +}; + +struct MtShadowTagPool +{ + usz_t capacity; + MtShadowTag *allocation; + MtShadowTag *first_free; + MtShadowTagPool *continuation; +}; + +struct MtShadowTagNameArena +{ + usz_t capacity; + usz_t usage; + char *allocation; + MtShadowTagNameArena *continuation; +}; + +struct MtShadowTagName +{ + char *string_in_arena; + u32_t identifier; +}; + +struct MtShadowTagNameRegistry +{ + usz_t names_capacity; + usz_t num_names; + MtShadowTagName *names; + u32_t id_counter; + + MtShadowTagNameArena *root_arena; +}; + +struct MtShadowTagSystem +{ + MtShadowTagNameRegistry name_registry; + MtShadowTagPool root_pool; +}; + +void mt_init_shadow_tag_system(MtShadowTagSystem *tag_system); +void mt_cleanup_shadow_tag_system(MtShadowTagSystem *tag_system); + +MtShadowTagPool * mt_new_shadow_tag_pool(usz_t capacity); + +/// @brief Crates a new MtShadowTagPool with a given capacity. +/// @warning Don't use `mt_free_shadow_tag_pool()` with use created with this method. +/// It will result in a call to `free()` for the given pool, which may cause a crash. +/// @param pool A pointer to the location at which the pool should be created. +/// @param capacity The number of entity shadow tags which should be able to reside in +/// the first instance of the pool. The pool will allocate more once needed. +void mt_init_shadow_tag_pool(MtShadowTagPool *pool, usz_t capacity); +void mt_free_shadow_tag_pool(MtShadowTagPool *pool); + +MtShadowTag * mt_alloc_shadow_tag(void *context_ptr); +MtShadowTag * mt_alloc_shadow_tag_in_pool(MtShadowTagPool *pool); + +/// @brief Crates as new MtShadowTag, makes it the new first of the chain given as input and +/// returns the new chain start. The chain start should be set to the returned value +/// @param chain_start The current start of the singly linked list of tags which are +/// attached to a shadow (the start of the tag chain). +/// @return The new tag chain's start. +MtShadowTag * mt_alloc_shadow_tag_before(MtShadowTag *chain_start); +void mt_free_shadow_tag_chain(MtShadowTag *tag); + +u32_t mt_tag_name_to_id(void *context_ptr, const char *tag_name); + +#endif // MT_SHADOW_TAG_H diff --git a/core/src-c/shadow-tag.c b/core/src-c/shadow-tag.c new file mode 100644 index 0000000..3d05046 --- /dev/null +++ b/core/src-c/shadow-tag.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include + +void mt_init_shadow_tag_pool_allocation(MtShadowTagPool *pool, usz_t capacity) +{ + usz_t slot_index = 0; + while(slot_index < capacity) + { + pool->allocation[slot_index].pool = pool; + pool->allocation[slot_index].next = &pool->allocation[slot_index+1]; + ++slot_index; + } + pool->allocation[capacity - 1].next = NULL; +} + +void mt_init_shadow_tag_pool(MtShadowTagPool *pool, usz_t capacity) +{ + pool->capacity = capacity; + pool->allocation = calloc(sizeof(MtShadowTag), capacity); + pool->first_free = pool->allocation; + pool->continuation = NULL; + mt_init_shadow_tag_pool_allocation(pool, capacity); +} + +MtShadowTagPool * mt_new_shadow_tag_pool(usz_t capacity) +{ + MtShadowTagPool *pool = malloc(sizeof(MtShadowTagPool)); + mt_init_shadow_tag_pool(pool, capacity * 2); + return pool; +} + +void mt_free_shadow_tag_pool(MtShadowTagPool *pool) +{ + if(pool->continuation != NULL) + mt_free_shadow_tag_pool(pool->continuation); + free(pool->allocation); + free(pool); +} + +MtShadowTag * mt_alloc_shadow_tag_in_pool(MtShadowTagPool *pool) +{ + if(pool->first_free == NULL) + { + if(pool->continuation == NULL) + pool->continuation = mt_new_shadow_tag_pool(pool->capacity * 2); + return mt_alloc_shadow_tag_in_pool(pool->continuation); + } + MtShadowTag *allocated_tag = pool->first_free; + pool->first_free = allocated_tag->next; + + // Reset the tag's old data + rr_memset(allocated_tag, sizeof(MtShadowTag), 0x00); + allocated_tag->pool = pool; + + return allocated_tag; +} + +MtShadowTag * mt_alloc_shadow_tag(void *context_ptr) +{ + MtContext *context = context_ptr; + return mt_alloc_shadow_tag_in_pool(&context->shadow_tag_system.root_pool); +} + +MtShadowTag * mt_alloc_shadow_tag_before(MtShadowTag *chain_start) +{ + MtShadowTag *tag = mt_alloc_shadow_tag_in_pool(chain_start->pool); + tag->next = chain_start; + return tag; +} + +void mt_free_shadow_tag_chain(MtShadowTag *tag) +{ + MtShadowTagPool *pool = tag->pool; + MtShadowTag *last_tag = tag; + while(last_tag->next != NULL) + { + last_tag = last_tag->next; + } + last_tag->next = pool->first_free; + pool->first_free = tag; +} + + + +void mt_init_shadow_tag_name_arena(MtShadowTagNameArena *arena, usz_t size) +{ + arena->usage = 0; + arena->capacity = size; + arena->allocation = malloc(size); + arena->continuation = NULL; +} + +MtShadowTagNameArena * mt_new_shadow_tag_name_arena(usz_t size) +{ + MtShadowTagNameArena *arena = malloc(sizeof(MtShadowTagNameArena)); + mt_init_shadow_tag_name_arena(arena, size); + return arena; +} + +void mt_free_shadow_tag_name_arena(MtShadowTagNameArena *arena) +{ + if(arena->continuation != NULL) + mt_free_shadow_tag_name_arena(arena->continuation); + free(arena->allocation); + free(arena); +} + +void mt_init_shadow_tag_name_registry(MtShadowTagNameRegistry *name_registry) +{ + name_registry->root_arena = mt_new_shadow_tag_name_arena(4096); + name_registry->id_counter = 1; + name_registry->num_names = 0; + name_registry->names_capacity = 256; + name_registry->names = calloc(sizeof(MtShadowTagName), name_registry->names_capacity); +} + +void mt_cleanup_shadow_tag_name_registry(MtShadowTagNameRegistry *name_registry) +{ + mt_free_shadow_tag_name_arena(name_registry->root_arena); + free(name_registry->names); +} + +void mt_init_shadow_tag_system(MtShadowTagSystem *tag_system) +{ + mt_init_shadow_tag_name_registry(&tag_system->name_registry); + mt_init_shadow_tag_pool(&tag_system->root_pool, 8192); +} + +void mt_cleanup_shadow_tag_system(MtShadowTagSystem *tag_system) +{ + mt_free_shadow_tag_pool(&tag_system->root_pool); + mt_cleanup_shadow_tag_name_registry(&tag_system->name_registry); +} + + + +char * mt_shadow_tag_name_arena_alloc(MtShadowTagNameArena *arena, usz_t num_bytes) +{ + usz_t end_size = arena->usage + num_bytes; + if(end_size >= arena->capacity) + { + if(arena->continuation == NULL) + arena->continuation = mt_new_shadow_tag_name_arena(arena->capacity * 2); + return mt_shadow_tag_name_arena_alloc(arena->continuation, num_bytes); + } + char *allocation = arena->allocation + arena->usage; + arena->usage = end_size; + return allocation; +} + +u32_t mt_force_create_new_tag_name_entry(MtShadowTagNameRegistry *name_registry, const char *tag_name) +{ + if(name_registry->num_names >= name_registry->names_capacity) + { + name_registry->names_capacity *= 2; + name_registry->names = realloc(name_registry->names, sizeof(MtShadowTagName) * name_registry->names_capacity); + } + MtShadowTagName *name_entry = &name_registry->names[name_registry->num_names++]; + + usz_t len_tag_name = rr_measure_string(tag_name); + char *tag_name_copy = mt_shadow_tag_name_arena_alloc(name_registry->root_arena, len_tag_name+1); + rr_memcopy(tag_name_copy, tag_name, len_tag_name + 1); + + name_entry->string_in_arena = tag_name_copy; + name_entry->identifier = name_registry->id_counter++; + + return name_entry->identifier; +} + +u32_t mt_tag_name_to_id(void *context_ptr, const char *tag_name) +{ + MtContext *context = context_ptr; + MtShadowTagNameRegistry *name_registry = &context->shadow_tag_system.name_registry; + + usz_t name_index = 0; + while(name_index < name_registry->num_names) + { + if(rr_strings_equal(name_registry->names[name_index].string_in_arena, tag_name)) + return name_registry->names[name_index].identifier; + ++name_index; + } + return mt_force_create_new_tag_name_entry(name_registry, tag_name); +} + diff --git a/core/tests/internal/shadow-tag/include_paths.txt b/core/tests/internal/shadow-tag/include_paths.txt new file mode 100644 index 0000000..2dda37e --- /dev/null +++ b/core/tests/internal/shadow-tag/include_paths.txt @@ -0,0 +1 @@ +core/inc-c \ No newline at end of file diff --git a/core/tests/internal/shadow-tag/main.c b/core/tests/internal/shadow-tag/main.c new file mode 100644 index 0000000..759faba --- /dev/null +++ b/core/tests/internal/shadow-tag/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +typedef enum +{ + TEST_CASE_NONE = 0, + TEST_CASE_SHADOW_TAG_POOL_CREATION, + TEST_CASE_SHADOW_TAG_CHAIN_CREATION, + TEST_CASE_SHADOW_TAG_CHAIN_PREPEND, + TEST_CASE_FREE_SHADOW_TAG_CHAIN, + TEST_CASE_STRESSTEST +} TestCase; + +TestCase g_current_test_case = TEST_CASE_NONE; +int g_stresstest_iteration = 0; + +const char * stringify_test_case(TestCase test_case) +{ + switch(test_case) + { + case TEST_CASE_NONE: return "NONE"; + case TEST_CASE_SHADOW_TAG_POOL_CREATION: return "SHADOW_TAG_POOL_CREATION"; + case TEST_CASE_SHADOW_TAG_CHAIN_CREATION: return "SHADOW_TAG_CHAIN_CREATION"; + case TEST_CASE_SHADOW_TAG_CHAIN_PREPEND: return "SHADOW_TAG_CHAIN_PREPEND"; + case TEST_CASE_FREE_SHADOW_TAG_CHAIN: return "FREE_SHADOW_TAG_CHAIN"; + case TEST_CASE_STRESSTEST: return "STRESSTEST"; + } + return "?"; +} + +void signal_handler(int number) +{ + printf("FAIL: The program crashed because of a memory error in test: %s\n", + stringify_test_case(g_current_test_case)); + if(g_current_test_case == TEST_CASE_STRESSTEST) + printf("Iteration: %d\n", g_stresstest_iteration); + exit(-1); +} + +void test_heavy_use() +{ + g_current_test_case = TEST_CASE_STRESSTEST; + MtShadowTagPool *pool = mt_new_shadow_tag_pool(1024); + MtShadowTag *tag_chain = mt_alloc_shadow_tag_in_pool(pool); + + while(g_stresstest_iteration < (1024 * 1024)) + { + tag_chain = mt_alloc_shadow_tag_before(tag_chain); + ++g_stresstest_iteration; + } + mt_free_shadow_tag_chain(tag_chain); + mt_free_shadow_tag_pool(pool); +} + +void test_functionality() +{ + g_current_test_case = TEST_CASE_SHADOW_TAG_POOL_CREATION; + MtShadowTagPool *pool = mt_new_shadow_tag_pool(1024); + + g_current_test_case = TEST_CASE_SHADOW_TAG_CHAIN_CREATION; + MtShadowTag *tag_chain = mt_alloc_shadow_tag_in_pool(pool); + + g_current_test_case = TEST_CASE_SHADOW_TAG_CHAIN_PREPEND; + tag_chain = mt_alloc_shadow_tag_before(tag_chain); + + g_current_test_case = TEST_CASE_FREE_SHADOW_TAG_CHAIN; + mt_free_shadow_tag_chain(tag_chain); + mt_free_shadow_tag_pool(pool); +} + +int main(int argc, char **argv) +{ + signal(SIGSEGV, &signal_handler); + test_functionality(); + test_heavy_use(); + puts("Success."); + return 0; +}