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 CHANGED
@@ -148,7 +148,7 @@ if(LIB_ARCH)
148
148
  endif()
149
149
 
150
150
  install(FILES
151
- ${CMAKE_CURRENT_SOURCE_DIR}/include/common.h
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/emnapi_common.h"
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
  [![Build](https://github.com/toyobayashi/emnapi/actions/workflows/main.yml/badge.svg?branch=main)](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 `wasm32-unknown-unknown` target, [napi-rs support is comming soon](https://github.com/napi-rs/napi-rs/issues/796).
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
- const napiModule = emnapiCore.createNapiModule({
336
- context: emnapi.getDefaultContext()
337
- })
338
-
339
- fetch('./hello.wasm').then(res => res.arrayBuffer()).then(wasmBuffer => {
340
- return WebAssembly.instantiate(wasmBuffer, {
341
- env: {
342
- ...napiModule.imports.env,
343
- // Currently napi-rs imports all symbols from env module
344
- ...napiModule.imports.napi,
345
- ...napiModule.imports.emnapi
346
- },
347
- // clang
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 { createNapiModule } = require('@emnapi/core')
363
+ const { instantiateNapiModule } = require('@emnapi/core')
367
364
  const { getDefaultContext } = require('@emnapi/runtime')
368
365
  const { WASI } = require('wasi')
369
-
370
- const napiModule = createNapiModule({
371
- context: getDefaultContext()
372
- })
373
-
374
- const wasi = new WASI({ /* ... */ })
375
-
376
- WebAssembly.instantiate(require('fs').readFileSync('./hello.wasm'), {
377
- wasi_snapshot_preview1: wasi.wasiImport,
378
- env: {
379
- ...napiModule.imports.env,
380
- // Currently napi-rs imports all symbols from env module
381
- ...napiModule.imports.napi,
382
- ...napiModule.imports.emnapi
383
- },
384
- // clang
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 { createNapiModule } from '@emnapi/core'
389
+ import { instantiateNapiModule } from '@emnapi/core'
404
390
  import { getDefaultContext } from '@emnapi/runtime'
405
391
  import { WASI } from '@tybys/wasm-util'
406
- import { Volumn, createFsFromVolume } from 'memfs-browser'
407
-
408
- const napiModule = createNapiModule({
409
- context: getDefaultContext()
410
- })
411
-
412
- const fs = createFsFromVolume(Volume.from({ /* ... */ }))
413
- const wasi = new WASI({ fs, /* ... */ })
414
-
415
- WebAssembly.instantiate(wasmBuffer, {
416
- wasi_snapshot_preview1: wasi.wasiImport,
417
- env: {
418
- ...napiModule.imports.env,
419
- // Currently napi-rs imports all symbols from env module
420
- ...napiModule.imports.napi,
421
- ...napiModule.imports.emnapi
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 (Emscripten Only)
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
- target_compile_options(hello PRIVATE "-sUSE_PTHREADS=1")
768
- target_link_options(hello PRIVATE
769
- "-sALLOW_MEMORY_GROWTH=1"
770
- "-sEXPORTED_FUNCTIONS=['_malloc','_free']"
771
- "-sUSE_PTHREADS=1"
772
- "-sPTHREAD_POOL_SIZE=4"
773
- # try to specify stack size if you experience pthread errors
774
- "-sSTACK_SIZE=2MB"
775
- "-sDEFAULT_PTHREAD_STACK_SIZE=2MB"
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
 
@@ -1458,7 +1458,9 @@ var emnapiExternalMemory = {
1458
1458
  }
1459
1459
  return view;
1460
1460
  }
1461
- if (emnapiExternalMemory.isDetachedArrayBuffer(view.buffer) && emnapiExternalMemory.wasmMemoryViewTable.has(view)) {
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 (worker && !worker._emnapiSendListener) {
4671
- worker._emnapiSendListener = function _emnapiSendListener(e) {
4672
- var data = ENVIRONMENT_IS_NODE ? e : e.data;
4673
- if (data.emnapiAsyncSend) {
4674
- if (ENVIRONMENT_IS_PTHREAD) {
4675
- postMessage({
4676
- emnapiAsyncSend: data.emnapiAsyncSend
4677
- });
4678
- }
4679
- else {
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.on('message', worker._emnapiSendListener);
4692
+ worker.off('message', handler);
4688
4693
  }
4689
4694
  else {
4690
- worker.addEventListener('message', worker._emnapiSendListener, false);
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
- emnapiAsyncSend: {
4704
- callback: callback,
4705
- data: data
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
- return emnapiImplement.apply(null, arguments);
4988
+ emnapiImplement.apply(null, arguments);
4972
4989
  }
4973
4990
  function emnapiImplementInternal() {
4974
- return emnapiImplement.apply(null, arguments);
4991
+ emnapiImplement.apply(null, arguments);
4975
4992
  }
4976
4993
  // $emnapi*
4977
4994
  function emnapiImplementHelper(name, sig, compilerTimeFunction, deps, _exportName) {
4978
- return emnapiImplement(name, sig, compilerTimeFunction, deps);
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
@@ -2,7 +2,7 @@
2
2
  #define EMNAPI_INCLUDE_EMNAPI_H_
3
3
 
4
4
  #include "js_native_api.h"
5
- #include "common.h"
5
+ #include "emnapi_common.h"
6
6
 
7
7
  typedef enum {
8
8
  emnapi_runtime,
@@ -22,7 +22,7 @@
22
22
  #endif
23
23
 
24
24
  #include "js_native_api_types.h"
25
- #include "common.h"
25
+ #include "emnapi_common.h"
26
26
 
27
27
  #define NAPI_AUTO_LENGTH SIZE_MAX
28
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emnapi",
3
- "version": "0.32.2",
3
+ "version": "0.33.0",
4
4
  "description": "Node-API implementation for Emscripten",
5
5
  "main": "index.js",
6
6
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- #include "emnapi_common.h"
1
+ #include "emnapi_internal.h"
2
2
  #include "node_api.h"
3
3
 
4
4
  EXTERN_C_START
@@ -1,5 +1,5 @@
1
1
  #include <node_api.h>
2
- #include "emnapi_common.h"
2
+ #include "emnapi_internal.h"
3
3
 
4
4
  EXTERN_C_START
5
5
 
package/src/async_work.c CHANGED
@@ -1,5 +1,5 @@
1
1
  #include "node_api.h"
2
- #include "emnapi_common.h"
2
+ #include "emnapi_internal.h"
3
3
 
4
4
  #if EMNAPI_HAVE_THREADS
5
5
 
package/src/emnapi.c CHANGED
@@ -1,4 +1,4 @@
1
- #include "emnapi_common.h"
1
+ #include "emnapi_internal.h"
2
2
 
3
3
  EXTERN_C_START
4
4
 
@@ -1,4 +1,4 @@
1
- #include "emnapi_common.h"
1
+ #include "emnapi_internal.h"
2
2
 
3
3
  #ifdef __EMSCRIPTEN__
4
4
  #include <emscripten/heap.h>
package/src/node_api.c CHANGED
@@ -1,4 +1,4 @@
1
- #include "emnapi_common.h"
1
+ #include "emnapi_internal.h"
2
2
  #include "node_api.h"
3
3
 
4
4
  #if EMNAPI_HAVE_THREADS
@@ -1,5 +1,5 @@
1
1
  #include "node_api.h"
2
- #include "emnapi_common.h"
2
+ #include "emnapi_internal.h"
3
3
 
4
4
  #if NAPI_VERSION >= 4 && EMNAPI_HAVE_THREADS
5
5
  #include <stdatomic.h>
@@ -27,7 +27,11 @@
27
27
  #include <errno.h>
28
28
  #include <string.h>
29
29
  #include "uv-common.h"
30
- #include "common.h"
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
- #ifndef _WIN32
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
- #ifndef _WIN32
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
 
@@ -27,7 +27,7 @@
27
27
  #include <stdlib.h>
28
28
  #include <sched.h>
29
29
  #include "../uv-common.h"
30
- #include "common.h"
30
+ #include "emnapi_common.h"
31
31
 
32
32
  #if defined(__clang__) || \
33
33
  defined(__GNUC__) || \
@@ -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