diff --git a/crates/napi/src/bindgen_runtime/module_register.rs b/crates/napi/src/bindgen_runtime/module_register.rs index 4788611a..56f1fbcd 100644 --- a/crates/napi/src/bindgen_runtime/module_register.rs +++ b/crates/napi/src/bindgen_runtime/module_register.rs @@ -5,8 +5,7 @@ use std::hash::Hash; #[cfg(all(feature = "napi4", not(target_arch = "wasm32")))] use std::ops::Deref; use std::ptr; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; use std::thread::ThreadId; use once_cell::sync::Lazy; @@ -534,15 +533,19 @@ unsafe extern "C" fn napi_register_module_v1( }); #[cfg(all(windows, feature = "napi4", feature = "tokio_rt"))] + #[cfg(all(feature = "napi4", feature = "tokio_rt"))] { crate::tokio_runtime::ensure_runtime(); - crate::tokio_runtime::RT_REFERENCE_COUNT.fetch_add(1, Ordering::SeqCst); + static init_counter: AtomicUsize = AtomicUsize::new(0); + let cleanup_hook_payload = + init_counter.fetch_add(1, Ordering::Relaxed) as *mut std::ffi::c_void; + unsafe { sys::napi_add_env_cleanup_hook( env, Some(crate::tokio_runtime::drop_runtime), - ptr::null_mut(), + cleanup_hook_payload, ) }; } diff --git a/crates/napi/src/tokio_runtime.rs b/crates/napi/src/tokio_runtime.rs index 1b769b5d..5aaa97b7 100644 --- a/crates/napi/src/tokio_runtime.rs +++ b/crates/napi/src/tokio_runtime.rs @@ -24,8 +24,7 @@ fn create_runtime() -> Option { pub(crate) static RT: Lazy>> = Lazy::new(|| RwLock::new(create_runtime())); #[cfg(windows)] -pub(crate) static RT_REFERENCE_COUNT: std::sync::atomic::AtomicUsize = - std::sync::atomic::AtomicUsize::new(0); +static RT_REFERENCE_COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); /// Ensure that the Tokio runtime is initialized. /// In windows the Tokio runtime will be dropped when Node env exits. @@ -33,24 +32,23 @@ pub(crate) static RT_REFERENCE_COUNT: std::sync::atomic::AtomicUsize = /// So we need to ensure that the Tokio runtime is initialized when the Node env is created. #[cfg(windows)] pub(crate) fn ensure_runtime() { + use std::sync::atomic::Ordering; + let mut rt = RT.write().unwrap(); if rt.is_none() { *rt = create_runtime(); } + + RT_REFERENCE_COUNT.fetch_add(1, Ordering::Relaxed); } #[cfg(windows)] -pub(crate) unsafe extern "C" fn drop_runtime(arg: *mut std::ffi::c_void) { +pub(crate) unsafe extern "C" fn drop_runtime(_arg: *mut std::ffi::c_void) { use std::sync::atomic::Ordering; - if RT_REFERENCE_COUNT.fetch_sub(1, Ordering::SeqCst) == 1 { + if RT_REFERENCE_COUNT.fetch_sub(1, Ordering::AcqRel) == 1 { RT.write().unwrap().take(); } - - unsafe { - let env: sys::napi_env = arg as *mut sys::napi_env__; - sys::napi_remove_env_cleanup_hook(env, Some(drop_runtime), arg); - } } /// Spawns a future onto the Tokio runtime. diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap deleted file mode 100644 index abcd4363..00000000 Binary files a/examples/napi/__test__/typegen.spec.ts.snap and /dev/null differ diff --git a/examples/napi/__tests__/unload.spec.js b/examples/napi/__tests__/unload.spec.js index 21a32ca2..2b9266e6 100644 --- a/examples/napi/__tests__/unload.spec.js +++ b/examples/napi/__tests__/unload.spec.js @@ -1,5 +1,7 @@ // use the commonjs syntax to prevent compiler from transpiling the module syntax +const path = require('path') + const test = require('ava').default test('unload module', (t) => { @@ -9,3 +11,12 @@ test('unload module', (t) => { const { add: add2 } = require('../index.node') t.is(add2(1, 2), 3) }) + +test('load module multi times', (t) => { + const { add } = require('../index.node') + t.is(add(1, 2), 3) + const { add: add2 } = require(path.toNamespacedPath( + path.join(__dirname, '../index.node'), + )) + t.is(add2(1, 2), 3) +}) diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 2c373e53..b0dbf3ae 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -389,6 +389,7 @@ test('return Undefined', (t) => { test('pass symbol in', (t) => { const sym = Symbol('test') const obj = setSymbolInObj(sym) + // @ts-expect-error t.is(obj[sym], 'a symbol') }) @@ -415,6 +416,7 @@ test('custom status code in Error', (t) => { }) test('function ts type override', (t) => { + // @ts-expect-error t.deepEqual(tsRename({ foo: 1, bar: 2, baz: 2 }), ['foo', 'bar', 'baz']) }) diff --git a/examples/napi/package.json b/examples/napi/package.json index 7d15eddc..f13384c9 100644 --- a/examples/napi/package.json +++ b/examples/napi/package.json @@ -18,13 +18,15 @@ "ava": { "extensions": [ "ts", - "tsx" + "tsx", + "js" ], "require": [ "ts-node/register/transpile-only" ], "files": [ - "__tests__/**/*.spec.ts" + "__tests__/**/*.spec.ts", + "__tests__/**/*.spec.js" ], "environmentVariables": { "TS_NODE_PROJECT": "../tsconfig.json" diff --git a/tsconfig.json b/tsconfig.json index d02b0536..664e01ca 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,8 +13,6 @@ "noUnusedParameters": true, "strict": true, "skipLibCheck": true, - "suppressImplicitAnyIndexErrors": true, - "suppressExcessPropertyErrors": true, "forceConsistentCasingInFileNames": true, "preserveSymlinks": true, "target": "ES2022",