emnapi 0.32.2 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +2 -2
- package/README.md +213 -97
- package/dist/library_napi.js +41 -24
- package/include/emnapi.h +1 -1
- package/include/js_native_api.h +1 -1
- package/package.json +1 -1
- package/src/async_cleanup_hook.c +1 -1
- package/src/async_context.c +1 -1
- package/src/async_work.c +1 -1
- package/src/emnapi.c +1 -1
- package/src/js_native_api.c +1 -1
- package/src/node_api.c +1 -1
- package/src/threadsafe_function.c +1 -1
- package/src/uv/threadpool.c +36 -5
- package/src/uv/unix/async.c +1 -1
- package/src/uv/unix/thread.c +10 -1
- /package/include/{common.h → emnapi_common.h} +0 -0
- /package/src/{emnapi_common.h → emnapi_internal.h} +0 -0
package/CMakeLists.txt
CHANGED
|
@@ -148,7 +148,7 @@ if(LIB_ARCH)
|
|
|
148
148
|
endif()
|
|
149
149
|
|
|
150
150
|
install(FILES
|
|
151
|
-
${CMAKE_CURRENT_SOURCE_DIR}/include/
|
|
151
|
+
${CMAKE_CURRENT_SOURCE_DIR}/include/emnapi_common.h
|
|
152
152
|
${CMAKE_CURRENT_SOURCE_DIR}/include/emnapi.h
|
|
153
153
|
${CMAKE_CURRENT_SOURCE_DIR}/include/js_native_api_types.h
|
|
154
154
|
${CMAKE_CURRENT_SOURCE_DIR}/include/js_native_api.h
|
|
@@ -170,7 +170,7 @@ install(FILES
|
|
|
170
170
|
if(EMNAPI_INSTALL_SRC)
|
|
171
171
|
install(FILES
|
|
172
172
|
${EMNAPI_SRC}
|
|
173
|
-
"${CMAKE_CURRENT_SOURCE_DIR}/src/
|
|
173
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/emnapi_internal.h"
|
|
174
174
|
DESTINATION "src/${PROJECT_NAME}")
|
|
175
175
|
install(DIRECTORY
|
|
176
176
|
${CMAKE_CURRENT_SOURCE_DIR}/src/uv
|
package/README.md
CHANGED
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/toyobayashi/emnapi/actions/workflows/main.yml)
|
|
8
8
|
|
|
9
|
-
[Node-API](https://nodejs.org/docs/latest/api/n-api.html) implementation for [Emscripten](https://emscripten.org/index.html), [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) and clang
|
|
10
|
-
|
|
11
|
-
Emscripten is the first class support target, currently thread related APIs are unavailable on `wasm32-unknown-unknown` and `wasm32-wasi` target.
|
|
9
|
+
[Node-API](https://nodejs.org/docs/latest/api/n-api.html) implementation for [Emscripten](https://emscripten.org/index.html), [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) and clang with wasm support. [napi-rs support is comming soon](https://github.com/napi-rs/napi-rs/tree/emnapi).
|
|
12
10
|
|
|
13
11
|
This project aims to
|
|
14
12
|
|
|
@@ -27,6 +25,16 @@ See documentation for more details:
|
|
|
27
25
|
|
|
28
26
|
[How to build Node-API official examples](https://github.com/toyobayashi/node-addon-examples)
|
|
29
27
|
|
|
28
|
+
Emscripten is the first class support target. If your target is running addon on browser,
|
|
29
|
+
we strongly recommend you to use Emscripten instead of wasi-sdk. Async works and threadsafe
|
|
30
|
+
functions related APIs are only available on Emscripten or `wasm32-wasi-threads` target since
|
|
31
|
+
they are relying on pthread. Though today we have [WASI browser polyfill](https://github.com/toyobayashi/wasm-util),
|
|
32
|
+
`wasm32-wasi-threads` is in very early stage and WASI itself is not designed for browser.
|
|
33
|
+
There are some limitations on browser about wasi-libc's pthread implementation, for example
|
|
34
|
+
`pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
|
|
35
|
+
which is disallowed in browser JS main thread. While Emscripten's pthread implementation
|
|
36
|
+
has considered usage in browser.
|
|
37
|
+
|
|
30
38
|
## Prerequests
|
|
31
39
|
|
|
32
40
|
You will need to install:
|
|
@@ -332,30 +340,19 @@ For non-emscripten, you need to use `@emnapi/core`. The initialization is simila
|
|
|
332
340
|
<script src="node_modules/@emnapi/runtime/dist/emnapi.min.js"></script>
|
|
333
341
|
<script src="node_modules/@emnapi/core/dist/emnapi-core.min.js"></script>
|
|
334
342
|
<script>
|
|
335
|
-
|
|
336
|
-
context: emnapi.getDefaultContext()
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
napi: napiModule.imports.napi,
|
|
349
|
-
emnapi: napiModule.imports.emnapi
|
|
350
|
-
})
|
|
351
|
-
}).then(({ instance, module }) => {
|
|
352
|
-
const binding = napiModule.init({
|
|
353
|
-
instance, // WebAssembly.Instance
|
|
354
|
-
module, // WebAssembly.Module
|
|
355
|
-
memory: instance.exports.memory, // WebAssembly.Memory
|
|
356
|
-
table: instance.exports.__indirect_function_table // WebAssembly.Table
|
|
357
|
-
})
|
|
358
|
-
// binding === napiModule.exports
|
|
343
|
+
emnapiCore.instantiateNapiModule(fetch('./hello.wasm'), {
|
|
344
|
+
context: emnapi.getDefaultContext(),
|
|
345
|
+
overwriteImports (importObject) {
|
|
346
|
+
// importObject.env = {
|
|
347
|
+
// ...importObject.env,
|
|
348
|
+
// ...importObject.napi,
|
|
349
|
+
// ...importObject.emnapi,
|
|
350
|
+
// // ...
|
|
351
|
+
// }
|
|
352
|
+
}
|
|
353
|
+
}).then(({ instance, module, napiModule }) => {
|
|
354
|
+
const binding = napiModule.exports
|
|
355
|
+
// ...
|
|
359
356
|
})
|
|
360
357
|
</script>
|
|
361
358
|
```
|
|
@@ -363,36 +360,25 @@ fetch('./hello.wasm').then(res => res.arrayBuffer()).then(wasmBuffer => {
|
|
|
363
360
|
Using WASI on Node.js
|
|
364
361
|
|
|
365
362
|
```js
|
|
366
|
-
const {
|
|
363
|
+
const { instantiateNapiModule } = require('@emnapi/core')
|
|
367
364
|
const { getDefaultContext } = require('@emnapi/runtime')
|
|
368
365
|
const { WASI } = require('wasi')
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
})
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
...
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
//
|
|
385
|
-
napi: napiModule.imports.napi,
|
|
386
|
-
emnapi: napiModule.imports.emnapi
|
|
387
|
-
}).then(({ instance, module }) => {
|
|
388
|
-
wasi.initialize(instance)
|
|
389
|
-
const binding = napiModule.init({
|
|
390
|
-
instance,
|
|
391
|
-
module,
|
|
392
|
-
memory: instance.exports.memory,
|
|
393
|
-
table: instance.exports.__indirect_function_table
|
|
394
|
-
})
|
|
395
|
-
// binding === napiModule.exports
|
|
366
|
+
const fs = require('fs')
|
|
367
|
+
|
|
368
|
+
instantiateNapiModule(fs.promises.readFile('./hello.wasm'), {
|
|
369
|
+
wasi: new WASI({ /* ... */ }),
|
|
370
|
+
context: getDefaultContext(),
|
|
371
|
+
overwriteImports (importObject) {
|
|
372
|
+
// importObject.env = {
|
|
373
|
+
// ...importObject.env,
|
|
374
|
+
// ...importObject.napi,
|
|
375
|
+
// ...importObject.emnapi,
|
|
376
|
+
// // ...
|
|
377
|
+
// }
|
|
378
|
+
}
|
|
379
|
+
}).then(({ instance, module, napiModule }) => {
|
|
380
|
+
const binding = napiModule.exports
|
|
381
|
+
// ...
|
|
396
382
|
})
|
|
397
383
|
```
|
|
398
384
|
|
|
@@ -400,38 +386,26 @@ Using WASI on browser, you can use WASI polyfill in [wasm-util](https://github.c
|
|
|
400
386
|
and [memfs-browser](https://github.com/toyobayashi/memfs-browser)
|
|
401
387
|
|
|
402
388
|
```js
|
|
403
|
-
import {
|
|
389
|
+
import { instantiateNapiModule } from '@emnapi/core'
|
|
404
390
|
import { getDefaultContext } from '@emnapi/runtime'
|
|
405
391
|
import { WASI } from '@tybys/wasm-util'
|
|
406
|
-
import {
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
})
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
// clang
|
|
424
|
-
napi: napiModule.imports.napi,
|
|
425
|
-
emnapi: napiModule.imports.emnapi
|
|
426
|
-
}).then(({ instance, module }) => {
|
|
427
|
-
wasi.initialize(instance)
|
|
428
|
-
const binding = napiModule.init({
|
|
429
|
-
instance,
|
|
430
|
-
module,
|
|
431
|
-
memory: instance.exports.memory,
|
|
432
|
-
table: instance.exports.__indirect_function_table
|
|
433
|
-
})
|
|
434
|
-
// binding === napiModule.exports
|
|
392
|
+
import { Volume, createFsFromVolume } from 'memfs-browser'
|
|
393
|
+
|
|
394
|
+
const fs = createFsFromVolume(Volume.fromJSON({ /* ... */ }))
|
|
395
|
+
return instantiateNapiModule(fetch('./hello.wasm'), {
|
|
396
|
+
wasi: new WASI({ fs, /* ... */ })
|
|
397
|
+
context: getDefaultContext(),
|
|
398
|
+
overwriteImports (importObject) {
|
|
399
|
+
// importObject.env = {
|
|
400
|
+
// ...importObject.env,
|
|
401
|
+
// ...importObject.napi,
|
|
402
|
+
// ...importObject.emnapi,
|
|
403
|
+
// // ...
|
|
404
|
+
// }
|
|
405
|
+
}
|
|
406
|
+
}).then(({ instance, module, napiModule }) => {
|
|
407
|
+
const binding = napiModule.exports
|
|
408
|
+
// ...
|
|
435
409
|
})
|
|
436
410
|
```
|
|
437
411
|
|
|
@@ -495,6 +469,7 @@ clang++ -O3 \
|
|
|
495
469
|
-L./node_modules/emnapi/lib/wasm32-wasi \
|
|
496
470
|
--target=wasm32-wasi \
|
|
497
471
|
--sysroot=$WASI_SDK_PATH/share/wasi-sysroot \
|
|
472
|
+
-fno-exceptions \
|
|
498
473
|
-mexec-model=reactor \
|
|
499
474
|
-Wl,--initial-memory=16777216 \
|
|
500
475
|
-Wl,--export-dynamic \
|
|
@@ -522,6 +497,7 @@ clang++ -O3 \
|
|
|
522
497
|
-I./node_modules/emnapi/include \
|
|
523
498
|
-L./node_modules/emnapi/lib/wasm32 \
|
|
524
499
|
--target=wasm32 \
|
|
500
|
+
-fno-exceptions \
|
|
525
501
|
-nostdlib \
|
|
526
502
|
-Wl,--no-entry \
|
|
527
503
|
-Wl,--initial-memory=16777216 \
|
|
@@ -752,35 +728,168 @@ pub unsafe extern "C" fn napi_register_wasm_v1(env: napi_env, exports: napi_valu
|
|
|
752
728
|
|
|
753
729
|
</details>
|
|
754
730
|
|
|
755
|
-
### Multithread
|
|
731
|
+
### Multithread
|
|
756
732
|
|
|
757
733
|
If you want to use async work or thread safe functions,
|
|
758
734
|
there are additional C source file need to be compiled and linking.
|
|
759
735
|
Recommend use CMake directly.
|
|
760
736
|
|
|
737
|
+
**This is EXPERIMENTAL on non-emscripten.**
|
|
738
|
+
|
|
761
739
|
```cmake
|
|
762
740
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/node_modules/emnapi")
|
|
763
741
|
|
|
764
742
|
add_executable(hello hello.c)
|
|
765
743
|
|
|
766
744
|
target_link_libraries(hello emnapi-mt)
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
"-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
745
|
+
|
|
746
|
+
if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
747
|
+
target_compile_options(hello PRIVATE "-sUSE_PTHREADS=1")
|
|
748
|
+
target_link_options(hello PRIVATE
|
|
749
|
+
"-sALLOW_MEMORY_GROWTH=1"
|
|
750
|
+
"-sEXPORTED_FUNCTIONS=['_malloc','_free']"
|
|
751
|
+
"-sUSE_PTHREADS=1"
|
|
752
|
+
"-sPTHREAD_POOL_SIZE=4"
|
|
753
|
+
# try to specify stack size if you experience pthread errors
|
|
754
|
+
"-sSTACK_SIZE=2MB"
|
|
755
|
+
"-sDEFAULT_PTHREAD_STACK_SIZE=2MB"
|
|
756
|
+
)
|
|
757
|
+
elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
|
|
758
|
+
# Experimental
|
|
759
|
+
target_compile_options(hello PRIVATE "-fno-exceptions" "-pthread")
|
|
760
|
+
target_link_options(hello PRIVATE
|
|
761
|
+
"-pthread"
|
|
762
|
+
"-mexec-model=reactor"
|
|
763
|
+
"-Wl,--import-memory"
|
|
764
|
+
"-Wl,--max-memory=2147483648"
|
|
765
|
+
"-Wl,--export-dynamic"
|
|
766
|
+
"-Wl,--export=malloc"
|
|
767
|
+
"-Wl,--export=free"
|
|
768
|
+
"-Wl,--import-undefined"
|
|
769
|
+
"-Wl,--export-table"
|
|
770
|
+
)
|
|
771
|
+
endif()
|
|
777
772
|
```
|
|
778
773
|
|
|
779
774
|
```bash
|
|
775
|
+
# emscripten
|
|
780
776
|
emcmake cmake -DCMAKE_BUILD_TYPE=Release -DEMNAPI_WORKER_POOL_SIZE=4 -G Ninja -H. -Bbuild
|
|
777
|
+
|
|
778
|
+
# wasi-sdk with thread support (Experimental)
|
|
779
|
+
cmake -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk-pthread.cmake \
|
|
780
|
+
-DWASI_SDK_PREFIX=$WASI_SDK_PATH \
|
|
781
|
+
-DCMAKE_BUILD_TYPE=Release \
|
|
782
|
+
-G Ninja -H. -Bbuild
|
|
783
|
+
|
|
781
784
|
cmake --build build
|
|
782
785
|
```
|
|
783
786
|
|
|
787
|
+
And additional work is required during instantiating wasm compiled with non-emscripten.
|
|
788
|
+
|
|
789
|
+
```js
|
|
790
|
+
// emnapi main thread (could be in a Worker)
|
|
791
|
+
instantiateNapiModule(input, {
|
|
792
|
+
context: getDefaultContext(),
|
|
793
|
+
wasi: new WASI(/* ... */),
|
|
794
|
+
// reuseWorker: true,
|
|
795
|
+
onCreateWorker () {
|
|
796
|
+
return new Worker('./worker.js')
|
|
797
|
+
// Node.js
|
|
798
|
+
// return new Worker(join(__dirname, './worker.js'), {
|
|
799
|
+
// env: process.env,
|
|
800
|
+
// execArgv: ['--experimental-wasi-unstable-preview1']
|
|
801
|
+
// })
|
|
802
|
+
},
|
|
803
|
+
overwriteImports (importObject) {
|
|
804
|
+
importObject.env.memory = new WebAssembly.Memory({
|
|
805
|
+
initial: 16777216 / 65536,
|
|
806
|
+
maximum: 2147483648 / 65536,
|
|
807
|
+
shared: true
|
|
808
|
+
})
|
|
809
|
+
}
|
|
810
|
+
})
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
```js
|
|
814
|
+
// worker.js
|
|
815
|
+
(function () {
|
|
816
|
+
let fs, WASI, emnapiCore
|
|
817
|
+
|
|
818
|
+
const ENVIRONMENT_IS_NODE =
|
|
819
|
+
typeof process === 'object' && process !== null &&
|
|
820
|
+
typeof process.versions === 'object' && process.versions !== null &&
|
|
821
|
+
typeof process.versions.node === 'string'
|
|
822
|
+
|
|
823
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
824
|
+
const nodeWorkerThreads = require('worker_threads')
|
|
825
|
+
|
|
826
|
+
const parentPort = nodeWorkerThreads.parentPort
|
|
827
|
+
|
|
828
|
+
parentPort.on('message', (data) => {
|
|
829
|
+
globalThis.onmessage({ data })
|
|
830
|
+
})
|
|
831
|
+
|
|
832
|
+
fs = require('fs')
|
|
833
|
+
|
|
834
|
+
Object.assign(globalThis, {
|
|
835
|
+
self: globalThis,
|
|
836
|
+
require,
|
|
837
|
+
Worker: nodeWorkerThreads.Worker,
|
|
838
|
+
importScripts: function (f) {
|
|
839
|
+
(0, eval)(fs.readFileSync(f, 'utf8') + '//# sourceURL=' + f)
|
|
840
|
+
},
|
|
841
|
+
postMessage: function (msg) {
|
|
842
|
+
parentPort.postMessage(msg)
|
|
843
|
+
}
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
WASI = require('./wasi').WASI
|
|
847
|
+
emnapiCore = require('@emnapi/core')
|
|
848
|
+
} else {
|
|
849
|
+
importScripts('./node_modules/memfs-browser/dist/memfs.js')
|
|
850
|
+
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.min.js')
|
|
851
|
+
importScripts('./node_modules/@emnapi/core/dist/emnapi-core.js')
|
|
852
|
+
emnapiCore = globalThis.emnapiCore
|
|
853
|
+
|
|
854
|
+
const { Volume, createFsFromVolume } = memfs
|
|
855
|
+
fs = createFsFromVolume(Volume.fromJSON({
|
|
856
|
+
'/': null
|
|
857
|
+
}))
|
|
858
|
+
|
|
859
|
+
WASI = globalThis.wasmUtil.WASI
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const { instantiateNapiModuleSync, MessageHandler } = emnapiCore
|
|
863
|
+
|
|
864
|
+
const handler = new MessageHandler({
|
|
865
|
+
onLoad ({ wasmModule, wasmMemory }) {
|
|
866
|
+
const wasi = new WASI({
|
|
867
|
+
fs,
|
|
868
|
+
print: ENVIRONMENT_IS_NODE
|
|
869
|
+
? (...args) => {
|
|
870
|
+
const str = require('util').format(...args)
|
|
871
|
+
fs.writeSync(1, str + '\n')
|
|
872
|
+
}
|
|
873
|
+
: function () { console.log.apply(console, arguments) }
|
|
874
|
+
})
|
|
875
|
+
|
|
876
|
+
return instantiateNapiModuleSync(wasmModule, {
|
|
877
|
+
childThread: true,
|
|
878
|
+
wasi,
|
|
879
|
+
overwriteImports (importObject) {
|
|
880
|
+
importObject.env.memory = wasmMemory
|
|
881
|
+
}
|
|
882
|
+
})
|
|
883
|
+
}
|
|
884
|
+
})
|
|
885
|
+
|
|
886
|
+
globalThis.onmessage = function (e) {
|
|
887
|
+
handler.handle(e)
|
|
888
|
+
// handle other messages
|
|
889
|
+
}
|
|
890
|
+
})()
|
|
891
|
+
```
|
|
892
|
+
|
|
784
893
|
## Preprocess Macro Options
|
|
785
894
|
|
|
786
895
|
### `-DEMNAPI_WORKER_POOL_SIZE=4`
|
|
@@ -794,6 +903,13 @@ Module.preRun.push(function () {
|
|
|
794
903
|
ENV.UV_THREADPOOL_SIZE = '2';
|
|
795
904
|
}
|
|
796
905
|
});
|
|
906
|
+
|
|
907
|
+
// wasi
|
|
908
|
+
new WASI({
|
|
909
|
+
env: {
|
|
910
|
+
UV_THREADPOOL_SIZE: '2'
|
|
911
|
+
}
|
|
912
|
+
})
|
|
797
913
|
```
|
|
798
914
|
|
|
799
915
|
It represent max of `EMNAPI_WORKER_POOL_SIZE` async work (`napi_queue_async_work`) can be executed in parallel. Default is not defined, read `UV_THREADPOOL_SIZE` at runtime.
|
|
@@ -818,7 +934,7 @@ Tell emnapi how to delay async work in `uv_async_send` / `uv__async_close`.
|
|
|
818
934
|
|
|
819
935
|
### `-DEMNAPI_USE_PROXYING=1`
|
|
820
936
|
|
|
821
|
-
This option only has effect if you use `-sUSE_PTHREADS`. Default is `1` if emscripten version `>= 3.1.9`, else `0`.
|
|
937
|
+
This option only has effect if you use emscripten `-sUSE_PTHREADS`. Default is `1` if emscripten version `>= 3.1.9`, else `0`.
|
|
822
938
|
|
|
823
939
|
- `0`
|
|
824
940
|
|
package/dist/library_napi.js
CHANGED
|
@@ -1458,7 +1458,9 @@ var emnapiExternalMemory = {
|
|
|
1458
1458
|
}
|
|
1459
1459
|
return view;
|
|
1460
1460
|
}
|
|
1461
|
-
|
|
1461
|
+
var maybeOldWasmMemory = emnapiExternalMemory.isDetachedArrayBuffer(view.buffer) ||
|
|
1462
|
+
((typeof SharedArrayBuffer === 'function') && (view.buffer instanceof SharedArrayBuffer));
|
|
1463
|
+
if (maybeOldWasmMemory && emnapiExternalMemory.wasmMemoryViewTable.has(view)) {
|
|
1462
1464
|
var info = emnapiExternalMemory.wasmMemoryViewTable.get(view);
|
|
1463
1465
|
var Ctor = info.Ctor;
|
|
1464
1466
|
var newView = void 0;
|
|
@@ -4667,29 +4669,41 @@ mergeInto(LibraryManager.library, {
|
|
|
4667
4669
|
'return r;' +
|
|
4668
4670
|
'}; })();',
|
|
4669
4671
|
$emnapiAddSendListener: function (worker) {
|
|
4670
|
-
if (
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4681
|
-
var callback = data.emnapiAsyncSend.callback;
|
|
4682
|
-
{{{ makeDynCall('vp', 'callback') }}}(data.emnapiAsyncSend.data);
|
|
4683
|
-
}
|
|
4672
|
+
if (!worker)
|
|
4673
|
+
return false;
|
|
4674
|
+
if (worker._emnapiSendListener)
|
|
4675
|
+
return true;
|
|
4676
|
+
var handler = function (e) {
|
|
4677
|
+
var data = ENVIRONMENT_IS_NODE ? e : e.data;
|
|
4678
|
+
var __emnapi__ = data.__emnapi__;
|
|
4679
|
+
if (__emnapi__ && __emnapi__.type === 'async-send') {
|
|
4680
|
+
if (ENVIRONMENT_IS_PTHREAD) {
|
|
4681
|
+
postMessage({ __emnapi__: __emnapi__ });
|
|
4684
4682
|
}
|
|
4685
|
-
|
|
4683
|
+
else {
|
|
4684
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4685
|
+
var callback = __emnapi__.payload.callback;
|
|
4686
|
+
{{{ makeDynCall('vp', 'callback') }}}(__emnapi__.payload.data);
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
};
|
|
4690
|
+
var dispose = function () {
|
|
4686
4691
|
if (ENVIRONMENT_IS_NODE) {
|
|
4687
|
-
worker.
|
|
4692
|
+
worker.off('message', handler);
|
|
4688
4693
|
}
|
|
4689
4694
|
else {
|
|
4690
|
-
worker.
|
|
4695
|
+
worker.removeEventListener('message', handler, false);
|
|
4691
4696
|
}
|
|
4697
|
+
delete worker._emnapiSendListener;
|
|
4698
|
+
};
|
|
4699
|
+
worker._emnapiSendListener = { handler: handler, dispose: dispose };
|
|
4700
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
4701
|
+
worker.on('message', handler);
|
|
4692
4702
|
}
|
|
4703
|
+
else {
|
|
4704
|
+
worker.addEventListener('message', handler, false);
|
|
4705
|
+
}
|
|
4706
|
+
return true;
|
|
4693
4707
|
},
|
|
4694
4708
|
_emnapi_async_send_js__sig: 'vipp',
|
|
4695
4709
|
_emnapi_async_send_js__deps: [
|
|
@@ -4700,9 +4714,12 @@ mergeInto(LibraryManager.library, {
|
|
|
4700
4714
|
_emnapi_async_send_js: function (type, callback, data) {
|
|
4701
4715
|
if (ENVIRONMENT_IS_PTHREAD) {
|
|
4702
4716
|
postMessage({
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4717
|
+
__emnapi__: {
|
|
4718
|
+
type: 'async-send',
|
|
4719
|
+
payload: {
|
|
4720
|
+
callback: callback,
|
|
4721
|
+
data: data
|
|
4722
|
+
}
|
|
4706
4723
|
}
|
|
4707
4724
|
});
|
|
4708
4725
|
}
|
|
@@ -4968,14 +4985,14 @@ function emnapiImplement(name, sig, compilerTimeFunction, deps) {
|
|
|
4968
4985
|
mergeInto(LibraryManager.library, sym);
|
|
4969
4986
|
}
|
|
4970
4987
|
function emnapiImplement2() {
|
|
4971
|
-
|
|
4988
|
+
emnapiImplement.apply(null, arguments);
|
|
4972
4989
|
}
|
|
4973
4990
|
function emnapiImplementInternal() {
|
|
4974
|
-
|
|
4991
|
+
emnapiImplement.apply(null, arguments);
|
|
4975
4992
|
}
|
|
4976
4993
|
// $emnapi*
|
|
4977
4994
|
function emnapiImplementHelper(name, sig, compilerTimeFunction, deps, _exportName) {
|
|
4978
|
-
|
|
4995
|
+
emnapiImplement(name, sig, compilerTimeFunction, deps);
|
|
4979
4996
|
}
|
|
4980
4997
|
function emnapiDefineVar(name, value, deps, postset) {
|
|
4981
4998
|
var _a;
|
package/include/emnapi.h
CHANGED
package/include/js_native_api.h
CHANGED
package/package.json
CHANGED
package/src/async_cleanup_hook.c
CHANGED
package/src/async_context.c
CHANGED
package/src/async_work.c
CHANGED
package/src/emnapi.c
CHANGED
package/src/js_native_api.c
CHANGED
package/src/node_api.c
CHANGED
package/src/uv/threadpool.c
CHANGED
|
@@ -27,7 +27,11 @@
|
|
|
27
27
|
#include <errno.h>
|
|
28
28
|
#include <string.h>
|
|
29
29
|
#include "uv-common.h"
|
|
30
|
-
#include "
|
|
30
|
+
#include "emnapi_common.h"
|
|
31
|
+
|
|
32
|
+
#if defined(__wasi__) && defined(_REENTRANT)
|
|
33
|
+
#define __EMNAPI_WASI_THREADS__
|
|
34
|
+
#endif
|
|
31
35
|
|
|
32
36
|
#define MAX_THREADPOOL_SIZE 1024
|
|
33
37
|
|
|
@@ -54,6 +58,15 @@ static void uv__cancelled(struct uv__work* w) {
|
|
|
54
58
|
|
|
55
59
|
EMNAPI_INTERNAL_EXTERN void _emnapi_worker_unref(uv_thread_t pid);
|
|
56
60
|
|
|
61
|
+
#ifdef __EMNAPI_WASI_THREADS__
|
|
62
|
+
EMNAPI_INTERNAL_EXTERN
|
|
63
|
+
void _emnapi_after_uvthreadpool_ready(void (*callback)(QUEUE* w, enum uv__work_kind kind),
|
|
64
|
+
QUEUE* w,
|
|
65
|
+
enum uv__work_kind kind);
|
|
66
|
+
EMNAPI_INTERNAL_EXTERN void _emnapi_tell_js_uvthreadpool(uv_thread_t* threads, unsigned int n);
|
|
67
|
+
EMNAPI_INTERNAL_EXTERN void _emnapi_emit_async_thread_ready();
|
|
68
|
+
#endif
|
|
69
|
+
|
|
57
70
|
/* To avoid deadlock with uv_cancel() it's crucial that the worker
|
|
58
71
|
* never holds the global mutex and the loop-local mutex at the same time.
|
|
59
72
|
*/
|
|
@@ -61,8 +74,11 @@ static void* worker(void* arg) {
|
|
|
61
74
|
struct uv__work* w;
|
|
62
75
|
QUEUE* q;
|
|
63
76
|
int is_slow_work;
|
|
64
|
-
|
|
77
|
+
#ifndef __EMNAPI_WASI_THREADS__
|
|
65
78
|
uv_sem_post((uv_sem_t*) arg);
|
|
79
|
+
#else
|
|
80
|
+
_emnapi_emit_async_thread_ready();
|
|
81
|
+
#endif
|
|
66
82
|
arg = NULL;
|
|
67
83
|
|
|
68
84
|
uv_mutex_lock(&mutex);
|
|
@@ -199,7 +215,9 @@ static void init_threads(void) {
|
|
|
199
215
|
#if !defined(EMNAPI_WORKER_POOL_SIZE) || !(EMNAPI_WORKER_POOL_SIZE > 0)
|
|
200
216
|
const char* val;
|
|
201
217
|
#endif
|
|
218
|
+
#ifndef __EMNAPI_WASI_THREADS__
|
|
202
219
|
uv_sem_t sem;
|
|
220
|
+
#endif
|
|
203
221
|
|
|
204
222
|
#if defined(EMNAPI_WORKER_POOL_SIZE) && EMNAPI_WORKER_POOL_SIZE > 0
|
|
205
223
|
nthreads = EMNAPI_WORKER_POOL_SIZE;
|
|
@@ -233,24 +251,33 @@ static void init_threads(void) {
|
|
|
233
251
|
QUEUE_INIT(&slow_io_pending_wq);
|
|
234
252
|
QUEUE_INIT(&run_slow_work_message);
|
|
235
253
|
|
|
254
|
+
#ifndef __EMNAPI_WASI_THREADS__
|
|
236
255
|
if (uv_sem_init(&sem, 0))
|
|
237
256
|
abort();
|
|
257
|
+
#endif
|
|
238
258
|
|
|
239
259
|
for (i = 0; i < nthreads; i++)
|
|
260
|
+
#ifndef __EMNAPI_WASI_THREADS__
|
|
240
261
|
if (uv_thread_create(threads + i, (uv_thread_cb) worker, &sem))
|
|
262
|
+
#else
|
|
263
|
+
if (uv_thread_create(threads + i, (uv_thread_cb) worker, NULL))
|
|
264
|
+
#endif
|
|
241
265
|
abort();
|
|
242
266
|
|
|
267
|
+
#ifndef __EMNAPI_WASI_THREADS__
|
|
243
268
|
for (i = 0; i < nthreads; i++)
|
|
244
269
|
uv_sem_wait(&sem);
|
|
245
270
|
|
|
246
271
|
uv_sem_destroy(&sem);
|
|
247
|
-
|
|
248
272
|
for (i = 0; i < nthreads; i++)
|
|
249
273
|
_emnapi_worker_unref(*(threads + i));
|
|
274
|
+
#else
|
|
275
|
+
_emnapi_tell_js_uvthreadpool(threads, nthreads);
|
|
276
|
+
#endif
|
|
250
277
|
}
|
|
251
278
|
|
|
252
279
|
|
|
253
|
-
#
|
|
280
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
254
281
|
static void reset_once(void) {
|
|
255
282
|
uv_once_t child_once = UV_ONCE_INIT;
|
|
256
283
|
memcpy(&once, &child_once, sizeof(child_once));
|
|
@@ -259,7 +286,7 @@ static void reset_once(void) {
|
|
|
259
286
|
|
|
260
287
|
|
|
261
288
|
static void init_once(void) {
|
|
262
|
-
#
|
|
289
|
+
#if !defined(_WIN32) && !defined(__wasi__)
|
|
263
290
|
/* Re-initialize the threadpool after fork.
|
|
264
291
|
* Note that this discards the global mutex and condition as well
|
|
265
292
|
* as the work queue.
|
|
@@ -280,7 +307,11 @@ void uv__work_submit(uv_loop_t* loop,
|
|
|
280
307
|
w->loop = loop;
|
|
281
308
|
w->work = work;
|
|
282
309
|
w->done = done;
|
|
310
|
+
// #ifdef __EMNAPI_WASI_THREADS__
|
|
311
|
+
// _emnapi_after_uvthreadpool_ready(post, &w->wq, kind);
|
|
312
|
+
// #else
|
|
283
313
|
post(&w->wq, kind);
|
|
314
|
+
// #endif
|
|
284
315
|
}
|
|
285
316
|
|
|
286
317
|
|
package/src/uv/unix/async.c
CHANGED
package/src/uv/unix/thread.c
CHANGED
|
@@ -6,6 +6,15 @@
|
|
|
6
6
|
#include <time.h>
|
|
7
7
|
#include "uv.h"
|
|
8
8
|
|
|
9
|
+
// #define CHECK_RET(the_call) \
|
|
10
|
+
// do { \
|
|
11
|
+
// int r = (the_call); \
|
|
12
|
+
// if (r) { \
|
|
13
|
+
// fprintf(stderr, #the_call ": %d\n", r); \
|
|
14
|
+
// abort(); \
|
|
15
|
+
// } \
|
|
16
|
+
// } while (0)
|
|
17
|
+
|
|
9
18
|
void uv_sem_post(sem_t* sem) {
|
|
10
19
|
if (sem_post(sem))
|
|
11
20
|
abort();
|
|
@@ -39,7 +48,7 @@ void uv_once(pthread_once_t* guard, void (*callback)(void)) {
|
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
int uv_mutex_init(uv_mutex_t* mutex) {
|
|
42
|
-
#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
|
51
|
+
#if defined(__wasi__) || defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
|
|
43
52
|
return pthread_mutex_init(mutex, NULL);
|
|
44
53
|
#else
|
|
45
54
|
pthread_mutexattr_t attr;
|
|
File without changes
|
|
File without changes
|