From f4cbed543fee94788d6af5f61223c3a0274cda75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Fri, 25 Aug 2023 22:23:54 +0200 Subject: [PATCH] Make `lauf_asm_module` thread-safe --- include/lauf/asm/module.h | 5 +++- src/lauf/asm/module.cpp | 63 ++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/include/lauf/asm/module.h b/include/lauf/asm/module.h index c1e58bc..b3c1096 100644 --- a/include/lauf/asm/module.h +++ b/include/lauf/asm/module.h @@ -14,7 +14,10 @@ typedef struct lauf_asm_layout lauf_asm_layout; /// A module, which is a self-contained unit of lauf ASM. /// /// It consists of function definitions, declarations of externally provided functions, and global -/// memory. Each module corresponds to one (physical/virtual) source file. +/// memory. +/// +/// This is the only data structure that is thread-safe: multiple threads can each build part of it. +/// Note that `lauf_asm_builder` is not thread-safe; each thread needs their own. typedef struct lauf_asm_module lauf_asm_module; /// Global memory of a module. diff --git a/src/lauf/asm/module.cpp b/src/lauf/asm/module.cpp index 4ed70d7..3739d75 100644 --- a/src/lauf/asm/module.cpp +++ b/src/lauf/asm/module.cpp @@ -3,46 +3,64 @@ #include -#include +#include +#include +#include #include +#include + struct lauf_asm_module : lauf::intrinsic_arena { - const char* name; - lauf_asm_global* globals = nullptr; - lauf_asm_function* functions = nullptr; - lauf_asm_chunk* chunks = nullptr; - std::uint32_t globals_count = 0; - std::uint32_t functions_count = 0; + std::atomic name; + std::atomic debug_path = nullptr; - const char* debug_path = nullptr; + mutable std::shared_mutex mutex; + lauf_asm_global* globals = nullptr; + lauf_asm_function* functions = nullptr; + lauf_asm_chunk* chunks = nullptr; + std::uint32_t globals_count = 0; + std::uint32_t functions_count = 0; lauf::array_list inst_debug_locations; lauf_asm_module(lauf::arena_key key, const char* name) : lauf::intrinsic_arena(key), name(this->strdup(name)) {} - ~lauf_asm_module(); + ~lauf_asm_module() + { + auto chunk = chunks; + while (chunk != nullptr) + { + auto next = chunk->next; + lauf_asm_chunk::destroy(chunk); + chunk = next; + } + } }; void lauf::add_debug_locations(lauf_asm_module* mod, const inst_debug_location* ptr, size_t count) { + std::unique_lock lock(mod->mutex); for (auto i = 0u; i != count; ++i) mod->inst_debug_locations.push_back(*mod, ptr[i]); } lauf_asm_inst* lauf::allocate_instructions(lauf_asm_module* mod, size_t inst_count) { + std::unique_lock lock(mod->mutex); return mod->allocate(inst_count); } lauf::module_list lauf::get_globals(const lauf_asm_module* mod) { + std::shared_lock lock(mod->mutex); return {mod->globals, mod->globals_count}; } lauf::module_list lauf::get_functions(const lauf_asm_module* mod) { + std::shared_lock lock(mod->mutex); return {mod->functions, mod->functions_count}; } @@ -80,17 +98,6 @@ bool lauf_asm_debug_location_eq(lauf_asm_debug_location lhs, lauf_asm_debug_loca && lhs.length == rhs.length; } -lauf_asm_module::~lauf_asm_module() -{ - auto chunk = chunks; - while (chunk != nullptr) - { - auto next = chunk->next; - lauf_asm_chunk::destroy(chunk); - chunk = next; - } -} - lauf_asm_module* lauf_asm_create_module(const char* name) { return lauf_asm_module::create(name); @@ -103,6 +110,7 @@ void lauf_asm_destroy_module(lauf_asm_module* mod) void lauf_asm_set_module_debug_path(lauf_asm_module* mod, const char* path) { + std::unique_lock lock(mod->mutex); mod->debug_path = mod->strdup(path); } @@ -119,6 +127,8 @@ const char* lauf_asm_module_debug_path(const lauf_asm_module* mod) const lauf_asm_function* lauf_asm_find_function_by_name(const lauf_asm_module* mod, const char* _name) { + std::shared_lock lock(mod->mutex); + auto name = std::string_view(_name); for (auto fn = mod->functions; fn != nullptr; fn = fn->next) if (fn->name == name) @@ -130,6 +140,8 @@ const lauf_asm_function* lauf_asm_find_function_by_name(const lauf_asm_module* m const lauf_asm_function* lauf_asm_find_function_of_instruction(const lauf_asm_module* mod, const lauf_asm_inst* ip) { + std::shared_lock lock(mod->mutex); + for (auto fn = mod->functions; fn != nullptr; fn = fn->next) if (ip >= fn->insts && ip < fn->insts + fn->inst_count) return fn; @@ -140,6 +152,8 @@ const lauf_asm_function* lauf_asm_find_function_of_instruction(const lauf_asm_mo const lauf_asm_chunk* lauf_asm_find_chunk_of_instruction(const lauf_asm_module* mod, const lauf_asm_inst* ip) { + std::shared_lock lock(mod->mutex); + for (auto chunk = mod->chunks; chunk != nullptr; chunk = chunk->next) if (ip >= chunk->fn->insts && ip < chunk->fn->insts + chunk->fn->inst_count) return chunk; @@ -179,6 +193,8 @@ lauf_asm_debug_location find_debug_location( lauf_asm_debug_location lauf_asm_find_debug_location_of_instruction(const lauf_asm_module* mod, const lauf_asm_inst* ip) { + std::shared_lock lock(mod->mutex); + if (mod->inst_debug_locations.empty() && mod->chunks == nullptr) // Early exit, no debug locations are stored anywhere. return lauf_asm_debug_location_null; @@ -195,6 +211,7 @@ lauf_asm_debug_location lauf_asm_find_debug_location_of_instruction(const lauf_a lauf_asm_global* lauf_asm_add_global(lauf_asm_module* mod, lauf_asm_global_permissions perms) { + std::unique_lock lock(mod->mutex); return mod->construct(mod, perms == LAUF_ASM_GLOBAL_READ_WRITE); } @@ -206,11 +223,15 @@ void lauf_asm_define_data_global(lauf_asm_module* mod, lauf_asm_global* global, global->alignment = std::uint16_t(layout.alignment); if (data != nullptr) + { + std::unique_lock lock(mod->mutex); global->memory = mod->memdup(data, layout.size); + } } void lauf_asm_set_global_debug_name(lauf_asm_module* mod, lauf_asm_global* global, const char* name) { + std::unique_lock lock(mod->mutex); global->name = mod->strdup(name); } @@ -233,6 +254,7 @@ const char* lauf_asm_global_debug_name(const lauf_asm_global* global) lauf_asm_function* lauf_asm_add_function(lauf_asm_module* mod, const char* name, lauf_asm_signature sig) { + std::unique_lock lock(mod->mutex); return mod->construct(mod, name, sig); } @@ -264,6 +286,7 @@ size_t lauf_asm_get_instruction_index(const lauf_asm_function* fn, const lauf_as lauf_asm_chunk* lauf_asm_create_chunk(lauf_asm_module* mod) { + std::unique_lock lock(mod->mutex); return lauf_asm_chunk::create(mod); }