Skip to content

Commit

Permalink
feat: concurrency support (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaucy authored Oct 26, 2024
1 parent 540ec17 commit 5236dab
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 94 deletions.
7 changes: 0 additions & 7 deletions ecsact/wasm/detail/minst/minst.hh
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@ public:
import_resolver_t import_resolver
) -> std::variant<minst, minst_error>;

/**
* Create a new minst with internal memory copied over. If 'initialize' was
* already called then the memory should be identical, thus 'initialize'
* should not be called again.
*/
static auto copy(minst& other) -> minst;

minst(minst&& other);
~minst();

Expand Down
219 changes: 132 additions & 87 deletions ecsact/wasm/detail/wasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <iostream>
#include <array>
#include <cstddef>
#include <thread>
#include "ecsact/runtime/dynamic.h"
#include "ecsact/wasm/detail/minst/minst.hh"
#include "ecsact/wasm/detail/logger.hh"
Expand Down Expand Up @@ -70,21 +71,67 @@ struct minst_ecsact_system_impls {

auto trap_handler = ecsactsi_wasm_trap_handler{};

thread_local auto thread_minst = std::optional<minst_ecsact_system_impls>{};
auto all_minsts = std::vector<minst_ecsact_system_impls>{};
auto next_available_minst_index = std::atomic_size_t{};
thread_local auto thread_minst =
std::optional<std::reference_wrapper<minst_ecsact_system_impls>>{};

auto ensure_minst() -> minst_ecsact_system_impls& {
if(!thread_minst) {
auto index = ++next_available_minst_index % all_minsts.size();
thread_minst = all_minsts[index];
}

return thread_minst->get();
}

void ecsact_si_wasm_system_impl(ecsact_system_execution_context* ctx) {
auto system_id = ecsact_system_execution_context_id(ctx);
auto itr = thread_minst->sys_impl_exports.find(system_id);
assert(itr != thread_minst->sys_impl_exports.end());
auto& minst = ensure_minst();
auto system_id = ecsact_system_execution_context_id(ctx);
auto itr = minst.sys_impl_exports.find(system_id);
assert(itr != minst.sys_impl_exports.end());

auto mem_data = std::array<std::byte, 4096>{};
set_call_mem_data(mem_data.data(), mem_data.size());
defer {
set_call_mem_data(nullptr, 0);
};
call_mem_alloc(thread_minst->memory.memory);
call_mem_alloc(minst.memory.memory);
itr->second.func_call(call_mem_alloc(ctx));
}

auto get_system_impl_exports(
minst& inst,
int systems_count,
ecsact_system_like_id* system_ids,
const char** wasm_exports,
std::unordered_map<ecsact_system_like_id, minst_export>& system_impl_exports
) -> ecsactsi_wasm_error {
system_impl_exports.clear();
system_impl_exports.reserve(systems_count);

for(auto i = 0; systems_count > i; ++i) {
auto sys_id = system_ids[i];
auto system_impl_export_name = std::string_view{
wasm_exports[i],
std::strlen(wasm_exports[i]),
};

auto exp = inst.find_export(system_impl_export_name);

if(!exp) {
return ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND;
}

if(exp->kind() != WASM_EXTERN_FUNC) {
return ECSACTSI_WASM_ERR_EXPORT_INVALID;
}

system_impl_exports[sys_id] = *exp;
}

return ECSACTSI_WASM_OK;
}
} // namespace

void ecsactsi_wasm_last_error_message(
Expand Down Expand Up @@ -126,108 +173,106 @@ ecsactsi_wasm_error ecsactsi_wasm_load(
return ECSACTSI_WASM_ERR_NO_SET_SYSTEM_EXECUTION;
}
#endif

auto result = ecsact::wasm::detail::minst::create(
engine(),
std::span{
reinterpret_cast<std::byte*>(wasm_data),
static_cast<size_t>(wasm_data_size),
},
[&](const minst_import imp) -> minst_import_resolve_t {
auto module_name = imp.module();
auto method_name = imp.name();

if(imp.module() == "env") {
auto itr = guest_env_module_imports.find(method_name);
if(itr == guest_env_module_imports.end()) {
return std::nullopt;
}
return itr->second();
auto import_resolver = [&](const minst_import imp) -> minst_import_resolve_t {
auto module_name = imp.module();
auto method_name = imp.name();

if(imp.module() == "env") {
auto itr = guest_env_module_imports.find(method_name);
if(itr == guest_env_module_imports.end()) {
return std::nullopt;
}
return itr->second();
}

if(imp.module() == "wasi_snapshot_preview1") {
auto itr = guest_wasi_module_imports.find(method_name);
if(itr == guest_wasi_module_imports.end()) {
return std::nullopt;
}
return itr->second();
if(imp.module() == "wasi_snapshot_preview1") {
auto itr = guest_wasi_module_imports.find(method_name);
if(itr == guest_wasi_module_imports.end()) {
return std::nullopt;
}

return std::nullopt;
return itr->second();
}
);

if(std::holds_alternative<minst_error>(result)) {
auto err = std::get<minst_error>(result);
switch(err.code) {
case minst_error_code::ok:
assert(err.code != minst_error_code::ok);
case minst_error_code::compile_fail:
return ECSACTSI_WASM_ERR_COMPILE_FAIL;
case minst_error_code::unresolved_guest_import:
return ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID;
case minst_error_code::instantiate_fail:
return ECSACTSI_WASM_ERR_INSTANTIATE_FAIL;
}
}
return std::nullopt;
};

auto& inst = std::get<minst>(result);
auto system_impl_exports =
std::unordered_map<ecsact_system_like_id, minst_export>{};
all_minsts.reserve(100);

system_impl_exports.reserve(systems_count);
for(auto i = 0; 100 > i; ++i) {
auto result = minst::create(
engine(),
std::span{
reinterpret_cast<std::byte*>(wasm_data),
static_cast<size_t>(wasm_data_size),
},
import_resolver
);

for(auto i = 0; systems_count > i; ++i) {
auto sys_id = system_ids[i];
auto system_impl_export_name = std::string_view{
wasm_exports[i],
std::strlen(wasm_exports[i]),
};
if(std::holds_alternative<minst_error>(result)) {
auto err = std::get<minst_error>(result);
switch(err.code) {
case minst_error_code::ok:
assert(err.code != minst_error_code::ok);
case minst_error_code::compile_fail:
return ECSACTSI_WASM_ERR_COMPILE_FAIL;
case minst_error_code::unresolved_guest_import:
return ECSACTSI_WASM_ERR_GUEST_IMPORT_INVALID;
case minst_error_code::instantiate_fail:
return ECSACTSI_WASM_ERR_INSTANTIATE_FAIL;
}
}

auto exp = inst.find_export(system_impl_export_name);
auto& inst = std::get<minst>(result);
auto system_impl_exports =
std::unordered_map<ecsact_system_like_id, minst_export>{};

if(!exp) {
return ECSACTSI_WASM_ERR_EXPORT_NOT_FOUND;
}
auto err = get_system_impl_exports(
inst,
systems_count,
system_ids,
wasm_exports,
system_impl_exports
);

if(exp->kind() != WASM_EXTERN_FUNC) {
return ECSACTSI_WASM_ERR_EXPORT_INVALID;
if(err != ECSACTSI_WASM_OK) {
return err;
}

system_impl_exports[sys_id] = *exp;
}

auto wasm_mem = std::optional<minst_export>{};
auto wasm_mem = std::optional<minst_export>{};

for(auto exp : inst.exports()) {
if(exp.kind() == WASM_EXTERN_MEMORY) {
wasm_mem = exp;
break;
for(auto exp : inst.exports()) {
if(exp.kind() == WASM_EXTERN_MEMORY) {
wasm_mem = exp;
break;
}
}
}

assert(wasm_mem);
assert(wasm_mem);

auto mem_data = std::array<std::byte, 4096>{};
set_call_mem_data(mem_data.data(), mem_data.size());
call_mem_alloc<wasm_memory_t*>(wasm_mem->memory);
defer {
set_call_mem_data(nullptr, 0);
};
auto init_trap = inst.initialize();
if(init_trap) {
return ECSACTSI_WASM_ERR_INITIALIZE_FAIL;
}
auto mem_data = std::array<std::byte, 4096>{};
set_call_mem_data(mem_data.data(), mem_data.size());
call_mem_alloc<wasm_memory_t*>(wasm_mem->memory);
defer {
set_call_mem_data(nullptr, 0);
};
auto init_trap = inst.initialize();
if(init_trap) {
return ECSACTSI_WASM_ERR_INITIALIZE_FAIL;
}

for(auto&& [sys_id, exp] : system_impl_exports) {
ecsact_set_system_execution_impl(sys_id, &ecsact_si_wasm_system_impl);
all_minsts.emplace_back( //
std::move(inst),
system_impl_exports,
*wasm_mem
);
}

thread_minst.emplace( //
std::move(inst),
system_impl_exports,
*wasm_mem
);
for(auto i = 0; systems_count > i; ++i) {
ecsact_set_system_execution_impl(
system_ids[i],
&ecsact_si_wasm_system_impl
);
}

return ECSACTSI_WASM_OK;
}
Expand Down
1 change: 1 addition & 0 deletions test/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ bazel_dep(name = "ecsact_cli", version = "0.3.4")
bazel_dep(name = "rules_ecsact", version = "0.5.1")
bazel_dep(name = "xxhash", version = "0.8.2")
bazel_dep(name = "ecsact_si_wasm")

local_path_override(
module_name = "ecsact_si_wasm",
path = "..",
Expand Down

0 comments on commit 5236dab

Please sign in to comment.