emnapi 0.33.1 → 0.35.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 +43 -1
- package/README.md +93 -19
- package/dist/library_napi.js +1262 -425
- package/lib/wasm32/libdlmalloc-mt.a +0 -0
- package/lib/wasm32/libdlmalloc.a +0 -0
- package/lib/wasm32/libemmalloc-mt.a +0 -0
- package/lib/wasm32/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
- package/lib/wasm32-wasi/libemnapi-basic-mt.a +0 -0
- package/package.json +1 -1
- package/src/malloc/dlmalloc/malloc.c +2 -2
- package/src/thread/async_worker_create.c +76 -0
- package/src/thread/async_worker_init.S +33 -0
- package/src/threadsafe_function.c +3 -4
- package/src/uv/threadpool.c +9 -3
package/CMakeLists.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
cmake_minimum_required(VERSION 3.13)
|
|
2
2
|
|
|
3
|
-
project(emnapi)
|
|
3
|
+
project(emnapi LANGUAGES C ASM)
|
|
4
4
|
|
|
5
5
|
option(EMNAPI_INSTALL_SRC "EMNAPI_INSTALL_SRC" OFF)
|
|
6
6
|
option(EMNAPI_FIND_NODE_ADDON_API "EMNAPI_FIND_NODE_ADDON_API" OFF)
|
|
@@ -50,10 +50,13 @@ else()
|
|
|
50
50
|
endif()
|
|
51
51
|
|
|
52
52
|
set(EMNAPI_BASIC_TARGET_NAME "emnapi-basic")
|
|
53
|
+
set(EMNAPI_BASIC_MT_TARGET_NAME "emnapi-basic-mt")
|
|
53
54
|
set(EMNAPI_TARGET_NAME "emnapi")
|
|
54
55
|
set(EMNAPI_MT_TARGET_NAME "emnapi-mt")
|
|
55
56
|
set(DLMALLOC_TARGET_NAME "dlmalloc")
|
|
57
|
+
set(DLMALLOC_MT_TARGET_NAME "dlmalloc-mt")
|
|
56
58
|
set(EMMALLOC_TARGET_NAME "emmalloc")
|
|
59
|
+
set(EMMALLOC_MT_TARGET_NAME "emmalloc-mt")
|
|
57
60
|
|
|
58
61
|
if(EMNAPI_FIND_NODE_ADDON_API)
|
|
59
62
|
execute_process(
|
|
@@ -82,11 +85,26 @@ if(IS_WASM32)
|
|
|
82
85
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/dlmalloc/dlmalloc.c"
|
|
83
86
|
)
|
|
84
87
|
target_compile_definitions(${DLMALLOC_TARGET_NAME} PRIVATE "PAGESIZE=65536")
|
|
88
|
+
|
|
89
|
+
add_library(${DLMALLOC_MT_TARGET_NAME} STATIC
|
|
90
|
+
${MALLOC_PUBLIC_SOURCES}
|
|
91
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/dlmalloc/dlmalloc.c"
|
|
92
|
+
)
|
|
93
|
+
target_compile_options(${DLMALLOC_MT_TARGET_NAME} PUBLIC "-matomics" "-mbulk-memory")
|
|
94
|
+
target_compile_definitions(${DLMALLOC_MT_TARGET_NAME} PRIVATE "PAGESIZE=65536" "USE_LOCKS=1")
|
|
95
|
+
|
|
85
96
|
add_library(${EMMALLOC_TARGET_NAME} STATIC
|
|
86
97
|
${MALLOC_PUBLIC_SOURCES}
|
|
87
98
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/emmalloc/emmalloc.c"
|
|
88
99
|
)
|
|
89
100
|
target_compile_definitions(${EMMALLOC_TARGET_NAME} PRIVATE "PAGESIZE=65536")
|
|
101
|
+
|
|
102
|
+
add_library(${EMMALLOC_MT_TARGET_NAME} STATIC
|
|
103
|
+
${MALLOC_PUBLIC_SOURCES}
|
|
104
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/malloc/emmalloc/emmalloc.c"
|
|
105
|
+
)
|
|
106
|
+
target_compile_options(${EMMALLOC_MT_TARGET_NAME} PUBLIC "-matomics" "-mbulk-memory")
|
|
107
|
+
target_compile_definitions(${EMMALLOC_MT_TARGET_NAME} PRIVATE "PAGESIZE=65536" "__EMSCRIPTEN_SHARED_MEMORY__=1")
|
|
90
108
|
endif()
|
|
91
109
|
|
|
92
110
|
add_library(${EMNAPI_TARGET_NAME} STATIC ${EMNAPI_SRC} ${UV_SRC})
|
|
@@ -101,6 +119,22 @@ if(IS_EMSCRIPTEN)
|
|
|
101
119
|
target_link_options(${EMNAPI_BASIC_TARGET_NAME} INTERFACE "--js-library=${EMNAPI_JS_LIB}")
|
|
102
120
|
endif()
|
|
103
121
|
|
|
122
|
+
if(IS_WASM32 OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads"))
|
|
123
|
+
set(EMNAPI_BUILD_BASIC_MT ON)
|
|
124
|
+
else()
|
|
125
|
+
set(EMNAPI_BUILD_BASIC_MT OFF)
|
|
126
|
+
endif()
|
|
127
|
+
|
|
128
|
+
if(EMNAPI_BUILD_BASIC_MT)
|
|
129
|
+
add_library(${EMNAPI_BASIC_MT_TARGET_NAME} STATIC
|
|
130
|
+
${ENAPI_BASIC_SRC}
|
|
131
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_create.c"
|
|
132
|
+
"${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_init.S"
|
|
133
|
+
)
|
|
134
|
+
target_compile_options(${EMNAPI_BASIC_MT_TARGET_NAME} PUBLIC "-matomics" "-mbulk-memory")
|
|
135
|
+
target_include_directories(${EMNAPI_BASIC_MT_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
|
|
136
|
+
endif()
|
|
137
|
+
|
|
104
138
|
if(IS_EMSCRIPTEN OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads"))
|
|
105
139
|
set(EMNAPI_BUILD_MT ON)
|
|
106
140
|
else()
|
|
@@ -141,9 +175,14 @@ if(LIB_ARCH)
|
|
|
141
175
|
if(EMNAPI_BUILD_MT)
|
|
142
176
|
install(TARGETS ${EMNAPI_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
143
177
|
endif()
|
|
178
|
+
if(EMNAPI_BUILD_BASIC_MT)
|
|
179
|
+
install(TARGETS ${EMNAPI_BASIC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
180
|
+
endif()
|
|
144
181
|
if(IS_WASM32)
|
|
145
182
|
install(TARGETS ${DLMALLOC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
183
|
+
install(TARGETS ${DLMALLOC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
146
184
|
install(TARGETS ${EMMALLOC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
185
|
+
install(TARGETS ${EMMALLOC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
|
|
147
186
|
endif()
|
|
148
187
|
endif()
|
|
149
188
|
|
|
@@ -178,4 +217,7 @@ if(EMNAPI_INSTALL_SRC)
|
|
|
178
217
|
install(DIRECTORY
|
|
179
218
|
${CMAKE_CURRENT_SOURCE_DIR}/src/malloc
|
|
180
219
|
DESTINATION "src/${PROJECT_NAME}")
|
|
220
|
+
install(DIRECTORY
|
|
221
|
+
${CMAKE_CURRENT_SOURCE_DIR}/src/thread
|
|
222
|
+
DESTINATION "src/${PROJECT_NAME}")
|
|
181
223
|
endif()
|
package/README.md
CHANGED
|
@@ -6,7 +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 with wasm support.
|
|
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.
|
|
10
10
|
|
|
11
11
|
This project aims to
|
|
12
12
|
|
|
@@ -25,16 +25,6 @@ See documentation for more details:
|
|
|
25
25
|
|
|
26
26
|
[How to build Node-API official examples](https://github.com/toyobayashi/node-addon-examples)
|
|
27
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
|
-
|
|
38
28
|
## Prerequests
|
|
39
29
|
|
|
40
30
|
You will need to install:
|
|
@@ -275,6 +265,9 @@ declare namespace Module {
|
|
|
275
265
|
* napi_create_async_work and napi_create_threadsafe_function
|
|
276
266
|
*/
|
|
277
267
|
nodeBinding?: typeof import('@emnapi/node-binding')
|
|
268
|
+
|
|
269
|
+
/** See Multithread part */
|
|
270
|
+
asyncWorkPoolSize?: number
|
|
278
271
|
}
|
|
279
272
|
export function emnapiInit (options: EmnapiInitOptions): any
|
|
280
273
|
}
|
|
@@ -732,20 +725,60 @@ pub unsafe extern "C" fn napi_register_wasm_v1(env: napi_env, exports: napi_valu
|
|
|
732
725
|
|
|
733
726
|
### Multithread
|
|
734
727
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
728
|
+
Related API:
|
|
729
|
+
|
|
730
|
+
- [napi_*_async_work](https://nodejs.org/dist/latest/docs/api/n-api.html#napi_create_async_work)
|
|
731
|
+
- [napi_*_threadsafe_function](https://nodejs.org/dist/latest/docs/api/n-api.html#asynchronous-thread-safe-function-calls)
|
|
732
|
+
|
|
733
|
+
They are available in emnapi, but you need to know more details before you start to use them.
|
|
734
|
+
Now emnapi has 3 implementations of async work and 2 implementations of TSFN:
|
|
735
|
+
|
|
736
|
+
- Async work
|
|
737
|
+
- A. Libuv threadpool and pthread based implementation in C
|
|
738
|
+
- B. Single thread mock in JavaScript
|
|
739
|
+
- C. Web worker based implementation in C (stack allocation) and JavaScript
|
|
740
|
+
- TSFN
|
|
741
|
+
- D. Libuv and pthread based implementation in C
|
|
742
|
+
- E. Web worker based implementation in JavaScript
|
|
743
|
+
|
|
744
|
+
| | Library to Link | `wasm32-emscripten` | `wasm32` | `wasm32-wasi` | `wasm32-wasi-threads` |
|
|
745
|
+
|---|------------------------|---------------------|----------|---------------|-----------------------|
|
|
746
|
+
| A | libemnapi-mt.a | ✅ | ❌ | ❌ | ✅ |
|
|
747
|
+
| B | libemnapi-basic(-mt).a | ✅ | ✅ | ✅ | ✅ |
|
|
748
|
+
| C | libemnapi-basic-mt.a | ❌ | ✅ | ❌ | ✅ |
|
|
749
|
+
| D | libemnapi-mt.a | ✅ | ❌ | ❌ | ✅ |
|
|
750
|
+
| E | libemnapi-basic-mt.a | ✅ | ✅ | ✅ | ✅ |
|
|
738
751
|
|
|
739
|
-
|
|
752
|
+
There are some limitations on browser about wasi-libc's pthread implementation, for example
|
|
753
|
+
`pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
|
|
754
|
+
which is disallowed in browser JS main thread. While Emscripten's pthread implementation
|
|
755
|
+
has considered usage in browser. If you need to run your addon with multithreaded features on browser,
|
|
756
|
+
we recommend you use Emscripten A & D, or bare wasm32 C & E.
|
|
757
|
+
|
|
758
|
+
#### About Prebuilt Libraries
|
|
759
|
+
|
|
760
|
+
Prebuilt libraries can be found in the `lib` directory in `emnapi` npm package.
|
|
761
|
+
|
|
762
|
+
| Library | Description | `wasm32-emscripten` | `wasm32` | `wasm32-wasi` | `wasm32-wasi-threads` |
|
|
763
|
+
|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------|----------|---------------|-----------------------------------------|
|
|
764
|
+
| libemnapi.a | no atomics feature.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` always return `napi_generic_failure`. | ✅ | ✅ | ✅ | waiting wasi-sdk release thread support |
|
|
765
|
+
| libemnapi-mt.a | atomics feature enabled.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are based on pthread and libuv port. | ✅ | ❌ | ❌ | waiting wasi-sdk release thread support |
|
|
766
|
+
| libemnapi-basic.a | no atomics feature.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are imported from JavaScript land. | ✅ | ✅ | ✅ | waiting wasi-sdk release thread support |
|
|
767
|
+
| libemnapi-basic-mt.a | atomics feature enabled.<br/><br/> no libuv port.<br/><br/> `napi_*_async_work` and `napi_*_threadsafe_function` are imported from JavaScript land.<br/><br/> include `emnapi_async_worker_create` and `emnapi_async_worker_init` for WebWorker based async work implementation. | ❌ | ✅ | ✅ | waiting wasi-sdk release thread support |
|
|
768
|
+
| libdlmalloc.a | no atomics feature, no thread safe garanteed. | ❌ | ✅ | ❌ | ❌ |
|
|
769
|
+
| libdlmalloc-mt.a | atomics feature enabled, thread safe. | ❌ | ✅ | ❌ | ❌ |
|
|
770
|
+
| libemmalloc.a | no atomics feature, no thread safe garanteed. | ❌ | ✅ | ❌ | ❌ |
|
|
771
|
+
| libemmalloc-mt.a | atomics feature enabled, thread safe. | ❌ | ✅ | ❌ | ❌ |
|
|
772
|
+
|
|
773
|
+
#### Usage
|
|
740
774
|
|
|
741
775
|
```cmake
|
|
742
776
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/node_modules/emnapi")
|
|
743
777
|
|
|
744
778
|
add_executable(hello hello.c)
|
|
745
779
|
|
|
746
|
-
target_link_libraries(hello emnapi-mt)
|
|
747
|
-
|
|
748
780
|
if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
781
|
+
target_link_libraries(hello emnapi-mt)
|
|
749
782
|
target_compile_options(hello PRIVATE "-pthread")
|
|
750
783
|
target_link_options(hello PRIVATE
|
|
751
784
|
"-sALLOW_MEMORY_GROWTH=1"
|
|
@@ -758,6 +791,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
|
|
|
758
791
|
)
|
|
759
792
|
elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
|
|
760
793
|
# Experimental
|
|
794
|
+
target_link_libraries(hello emnapi-mt)
|
|
761
795
|
set_target_properties(hello PROPERTIES SUFFIX ".wasm")
|
|
762
796
|
target_compile_options(hello PRIVATE "-fno-exceptions" "-pthread")
|
|
763
797
|
target_link_options(hello PRIVATE
|
|
@@ -771,6 +805,19 @@ elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
|
|
|
771
805
|
"-Wl,--import-undefined"
|
|
772
806
|
"-Wl,--export-table"
|
|
773
807
|
)
|
|
808
|
+
elseif((CMAKE_C_COMPILER_TARGET STREQUAL "wasm32") OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-unknown-unknown"))
|
|
809
|
+
target_link_libraries(hello emnapi-basic-mt)
|
|
810
|
+
set_target_properties(hello PROPERTIES SUFFIX ".wasm")
|
|
811
|
+
target_compile_options(hello PRIVATE "-fno-exceptions" "-matomics" "-mbulk-memory")
|
|
812
|
+
target_link_options(hello PRIVATE
|
|
813
|
+
"-nostdlib"
|
|
814
|
+
"-Wl,--no-entry"
|
|
815
|
+
"-Wl,--export=napi_register_wasm_v1"
|
|
816
|
+
"-Wl,--export=emnapi_async_worker_create"
|
|
817
|
+
"-Wl,--export=emnapi_async_worker_init"
|
|
818
|
+
"-Wl,--import-memory,--shared-memory,--max-memory=2147483648,--import-undefined"
|
|
819
|
+
"-Wl,--export-dynamic,--export=malloc,--export=free,--export-table"
|
|
820
|
+
)
|
|
774
821
|
endif()
|
|
775
822
|
```
|
|
776
823
|
|
|
@@ -784,6 +831,11 @@ cmake -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk-pthread.cmake \
|
|
|
784
831
|
-DCMAKE_BUILD_TYPE=Release \
|
|
785
832
|
-G Ninja -H. -Bbuild
|
|
786
833
|
|
|
834
|
+
cmake -DCMAKE_TOOLCHAIN_FILE=node_modules/emnapi/cmake/wasm32.cmake \
|
|
835
|
+
-DWASI_SDK_PREFIX=$WASI_SDK_PATH \
|
|
836
|
+
-DCMAKE_BUILD_TYPE=Release \
|
|
837
|
+
-G Ninja -H. -Bbuild
|
|
838
|
+
|
|
787
839
|
cmake --build build
|
|
788
840
|
```
|
|
789
841
|
|
|
@@ -793,6 +845,15 @@ And additional work is required during instantiating wasm compiled with non-emsc
|
|
|
793
845
|
// emnapi main thread (could be in a Worker)
|
|
794
846
|
instantiateNapiModule(input, {
|
|
795
847
|
context: getDefaultContext(),
|
|
848
|
+
/**
|
|
849
|
+
* emscripten
|
|
850
|
+
* 0: no effect
|
|
851
|
+
* > 0: the same effect to UV_THREADPOOL_SIZE
|
|
852
|
+
* non-emscripten
|
|
853
|
+
* 0: single thread mock
|
|
854
|
+
* > 0 schedule async work in web worker
|
|
855
|
+
*/
|
|
856
|
+
asyncWorkPoolSize: 4, // 0: single thread mock, > 0: schedule async work in web worker
|
|
796
857
|
wasi: new WASI(/* ... */),
|
|
797
858
|
// reuseWorker: true,
|
|
798
859
|
onCreateWorker () {
|
|
@@ -890,17 +951,30 @@ instantiateNapiModule(input, {
|
|
|
890
951
|
|
|
891
952
|
### `-DEMNAPI_WORKER_POOL_SIZE=4`
|
|
892
953
|
|
|
893
|
-
This is [`UV_THREADPOOL_SIZE`](http://docs.libuv.org/en/v1.x/threadpool.html?highlight=UV_THREADPOOL_SIZE) equivalent at compile time, if not predefined, emnapi will read `UV_THREADPOOL_SIZE` from Emscripten [environment variable](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-environment-variables) at runtime
|
|
954
|
+
This is [`UV_THREADPOOL_SIZE`](http://docs.libuv.org/en/v1.x/threadpool.html?highlight=UV_THREADPOOL_SIZE) equivalent at compile time, if not predefined, emnapi will read `asyncWorkPoolSize` option or `UV_THREADPOOL_SIZE` from Emscripten [environment variable](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-environment-variables) at runtime:
|
|
894
955
|
|
|
895
956
|
```js
|
|
957
|
+
Module.init({
|
|
958
|
+
// ...
|
|
959
|
+
asyncWorkPoolSize: 2
|
|
960
|
+
})
|
|
961
|
+
|
|
962
|
+
// if asyncWorkPoolSize is not specified
|
|
896
963
|
Module.preRun = Module.preRun || [];
|
|
897
964
|
Module.preRun.push(function () {
|
|
898
965
|
if (typeof ENV !== 'undefined') {
|
|
899
966
|
ENV.UV_THREADPOOL_SIZE = '2';
|
|
900
967
|
}
|
|
901
968
|
});
|
|
969
|
+
```
|
|
902
970
|
|
|
971
|
+
```js
|
|
903
972
|
// wasi
|
|
973
|
+
instantiateNapiModule({
|
|
974
|
+
// ...
|
|
975
|
+
asyncWorkPoolSize: 2
|
|
976
|
+
})
|
|
977
|
+
// if asyncWorkPoolSize is not specified
|
|
904
978
|
new WASI({
|
|
905
979
|
env: {
|
|
906
980
|
UV_THREADPOOL_SIZE: '2'
|
|
@@ -908,7 +982,7 @@ new WASI({
|
|
|
908
982
|
})
|
|
909
983
|
```
|
|
910
984
|
|
|
911
|
-
It represent max of `EMNAPI_WORKER_POOL_SIZE` async work (`napi_queue_async_work`) can be executed in parallel. Default is not defined
|
|
985
|
+
It represent max of `EMNAPI_WORKER_POOL_SIZE` async work (`napi_queue_async_work`) can be executed in parallel. Default is not defined.
|
|
912
986
|
|
|
913
987
|
You can set both `PTHREAD_POOL_SIZE` and `EMNAPI_WORKER_POOL_SIZE` to `number of CPU cores` in general.
|
|
914
988
|
If you use another library function which may create `N` child threads in async work,
|