From 9bbc9a63844e072609ec05ce24113afdafa387b7 Mon Sep 17 00:00:00 2001 From: Vicente Eduardo Ferrer Garcia Date: Thu, 19 Dec 2024 03:34:31 +0100 Subject: [PATCH] Host destruction working properly with nodejs. --- source/loader/source/loader.c | 13 ++++++++- source/loaders/node_loader/CMakeLists.txt | 2 +- .../node_loader/bootstrap/lib/bootstrap.js | 6 ++++ .../node_loader/source/node_loader_impl.cpp | 6 ++-- .../source/node_loader_trampoline.cpp | 1 - source/metacall/source/metacall.c | 9 ++++++ source/metacall/source/metacall_link.c | 3 +- source/ports/node_port/CMakeLists.txt | 2 +- source/ports/node_port/index.js | 28 ++++++++++--------- 9 files changed, 49 insertions(+), 21 deletions(-) diff --git a/source/loader/source/loader.c b/source/loader/source/loader.c index 8fc490118..73803e7ed 100644 --- a/source/loader/source/loader.c +++ b/source/loader/source/loader.c @@ -210,7 +210,18 @@ int loader_initialize_host(const loader_tag tag) return 1; } - return loader_impl_initialize(&loader_manager, p, plugin_impl_type(p, loader_impl)); + if (loader_impl_initialize(&loader_manager, p, plugin_impl_type(p, loader_impl)) != 0) + { + return 1; + } + else + { + loader_manager_impl manager_impl = plugin_manager_impl_type(&loader_manager, loader_manager_impl); + + manager_impl->host = p; + + return 0; + } } int loader_is_initialized(const loader_tag tag) diff --git a/source/loaders/node_loader/CMakeLists.txt b/source/loaders/node_loader/CMakeLists.txt index 70108f53e..a9bf13c67 100644 --- a/source/loaders/node_loader/CMakeLists.txt +++ b/source/loaders/node_loader/CMakeLists.txt @@ -158,7 +158,7 @@ target_link_libraries(${target} ${META_PROJECT_NAME}::metacall # MetaCall library # TODO: Implement delayed load - # ${NodeJS_LIBRARY} # NodeJS library + ${NodeJS_LIBRARY} # NodeJS library PUBLIC ${DEFAULT_LIBRARIES} diff --git a/source/loaders/node_loader/bootstrap/lib/bootstrap.js b/source/loaders/node_loader/bootstrap/lib/bootstrap.js index 4f2c5b766..8201b220a 100644 --- a/source/loaders/node_loader/bootstrap/lib/bootstrap.js +++ b/source/loaders/node_loader/bootstrap/lib/bootstrap.js @@ -436,6 +436,12 @@ const startup = (impl, ptr, trampoline_exports) => { 'await_function': node_loader_trampoline_await_function(trampoline), 'await_future': node_loader_trampoline_await_future(trampoline), }); + + // This function must destroy all the loaders but + // delaying the NodeJS Loader library unloading + if (trampoline_exports) { + process.on('exit', () => trampoline.destroy(node_loader_ptr)); + } } catch (ex) { console.log('Exception in bootstrap.js trampoline initialization:', ex); } diff --git a/source/loaders/node_loader/source/node_loader_impl.cpp b/source/loaders/node_loader/source/node_loader_impl.cpp index b32154153..281221d40 100644 --- a/source/loaders/node_loader/source/node_loader_impl.cpp +++ b/source/loaders/node_loader/source/node_loader_impl.cpp @@ -4604,11 +4604,11 @@ int node_loader_impl_destroy(loader_impl impl) return 1; } - /* Call destroy function with thread safe */ - node_loader_impl_try_destroy(node_impl); - if (loader_impl_get_option_host(impl) == 0) { + /* Call destroy function with thread safe */ + node_loader_impl_try_destroy(node_impl); + /* Wait for node thread to finish */ uv_thread_join(&node_impl->thread); } diff --git a/source/loaders/node_loader/source/node_loader_trampoline.cpp b/source/loaders/node_loader/source/node_loader_trampoline.cpp index 6314d2d30..7ed654358 100644 --- a/source/loaders/node_loader/source/node_loader_trampoline.cpp +++ b/source/loaders/node_loader/source/node_loader_trampoline.cpp @@ -244,7 +244,6 @@ napi_value node_loader_trampoline_reject(napi_env env, napi_callback_info info) napi_value node_loader_trampoline_destroy(napi_env env, napi_callback_info info) { napi_status status; - const size_t args_size = 1; size_t argc = args_size; napi_value recv; diff --git a/source/metacall/source/metacall.c b/source/metacall/source/metacall.c index d7d19f815..0962d974e 100644 --- a/source/metacall/source/metacall.c +++ b/source/metacall/source/metacall.c @@ -72,6 +72,7 @@ static loader_path plugin_path = { 0 }; static int metacall_plugin_extension_load(void); static void *metacallv_method(void *target, const char *name, method_invoke_ptr call, vector v, void *args[], size_t size); static type_id *metacall_type_ids(void *args[], size_t size); +static void metacall_destructor(void); static void metacall_detour_destructor(void); /* -- Costructors -- */ @@ -111,10 +112,18 @@ portability_constructor(metacall_constructor) metacall_value_destroy(config[0].options); exit(1); } + + /* Register the destructor on exit */ + atexit(metacall_destructor); } } } +void metacall_destructor(void) +{ + metacall_destroy(); +} + /* -- Methods -- */ const char *metacall_serial(void) diff --git a/source/metacall/source/metacall_link.c b/source/metacall/source/metacall_link.c index d1343c52d..9bad2939a 100644 --- a/source/metacall/source/metacall_link.c +++ b/source/metacall/source/metacall_link.c @@ -92,7 +92,8 @@ void *metacall_link_hook(void *handle, const char *symbol) /* Intercept function if any */ void *ptr = set_get(metacall_link_table, (set_key)symbol); - log_write("metacall", LOG_LEVEL_DEBUG, "MetaCall detour link interception: %s -> %p", symbol, ptr); + /* TODO: Disable logs here until log is completely thread safe and async signal safe */ + /* log_write("metacall", LOG_LEVEL_DEBUG, "MetaCall detour link interception: %s -> %p", symbol, ptr); */ if (ptr != NULL) { diff --git a/source/ports/node_port/CMakeLists.txt b/source/ports/node_port/CMakeLists.txt index 9cbb94fbc..c6531650a 100644 --- a/source/ports/node_port/CMakeLists.txt +++ b/source/ports/node_port/CMakeLists.txt @@ -225,7 +225,7 @@ set(node_port_test_exec "${node_port_test}_executable") message(STATUS "Test ${node_port_test_exec}") add_test(NAME ${node_port_test_exec} - COMMAND ${NodeJS_EXECUTABLE} test/index.js + COMMAND ${NodeJS_EXECUTABLE} -e "require('./test.js').main()" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/source/ports/node_port/index.js b/source/ports/node_port/index.js index f96f870d7..2372b3fd5 100644 --- a/source/ports/node_port/index.js +++ b/source/ports/node_port/index.js @@ -22,10 +22,10 @@ const mod = require('module'); const path = require('path'); -const fs = require('fs').promises; +const fs = require('fs'); const { URL } = require('url'); /* TODO: RPC Loader */ -async function findFilesRecursively(dirPattern, filePattern, depthLimit = Infinity) { +const findFilesRecursively = (dirPattern, filePattern, depthLimit = Infinity) => { const stack = [{ dir: dirPattern, depth: 0 }]; const files = []; const dirRegex = new RegExp(dirPattern); @@ -43,11 +43,11 @@ async function findFilesRecursively(dirPattern, filePattern, depthLimit = Infini continue; } - const items = await fs.readdir(dir); + const items = fs.readdirSync(dir); for (const item of items) { const fullPath = path.join(dir, item); - const stat = await fs.stat(fullPath); + const stat = fs.statSync(fullPath); if (stat.isDirectory()) { stack.push({ dir: fullPath, depth: depth + 1 }); @@ -61,7 +61,7 @@ async function findFilesRecursively(dirPattern, filePattern, depthLimit = Infini } return files; -} +}; const platformInstallPaths = () => { switch (process.platform) { @@ -83,7 +83,7 @@ const platformInstallPaths = () => { } throw new Error(`Platform ${process.platform} not supported`) -} +}; const searchPaths = () => { const customPath = process.env['METACALL_INSTALL_PATH']; @@ -96,13 +96,13 @@ const searchPaths = () => { } return platformInstallPaths() -} +}; -const findLibrary = async () => { +const findLibrary = () => { const searchData = searchPaths(); for (const p of searchData.paths) { - const files = await findFilesRecursively(p, searchData.name, 0); + const files = findFilesRecursively(p, searchData.name, 0); if (files.length !== 0) { return files[0]; @@ -110,7 +110,7 @@ const findLibrary = async () => { } throw new Error('MetaCall library not found, if you have it in a special folder, define it through METACALL_INSTALL_PATH') -} +}; const addon = (() => { try { @@ -127,7 +127,9 @@ const addon = (() => { */ process.env['METACALL_HOST'] = 'node'; - findLibrary().then(library => { + try { + const library = findLibrary(); + const { constants } = require('os'); const m = { exports: {} }; @@ -148,10 +150,10 @@ const addon = (() => { process.argv = argv; return m.exports; - }).catch(err => { + } catch (err) { console.log(err); process.exit(1); - }); + } } })();