emnapi 1.4.5 → 1.5.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.
Files changed (41) hide show
  1. package/CMakeLists.txt +34 -0
  2. package/README.md +4 -2
  3. package/common.gypi +11 -0
  4. package/dist/library_napi.js +58 -3
  5. package/emnapi.gyp +18 -0
  6. package/include/node/emnapi.h +2 -2
  7. package/lib/wasm32/libdlmalloc-mt.a +0 -0
  8. package/lib/wasm32/libdlmalloc.a +0 -0
  9. package/lib/wasm32/libemmalloc-mt.a +0 -0
  10. package/lib/wasm32/libemmalloc.a +0 -0
  11. package/lib/wasm32/libemnapi-basic-mt.a +0 -0
  12. package/lib/wasm32/libemnapi-basic.a +0 -0
  13. package/lib/wasm32/libemnapi.a +0 -0
  14. package/lib/wasm32-emscripten/libemnapi-basic.a +0 -0
  15. package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
  16. package/lib/wasm32-emscripten/libemnapi.a +0 -0
  17. package/lib/wasm32-wasi/libemnapi-basic-mt.a +0 -0
  18. package/lib/wasm32-wasi/libemnapi-basic.a +0 -0
  19. package/lib/wasm32-wasi/libemnapi.a +0 -0
  20. package/lib/wasm32-wasi-threads/libemnapi-basic-mt.a +0 -0
  21. package/lib/wasm32-wasi-threads/libemnapi-basic-napi-rs-mt.a +0 -0
  22. package/lib/wasm32-wasi-threads/libemnapi-basic.a +0 -0
  23. package/lib/wasm32-wasi-threads/libemnapi-mt.a +0 -0
  24. package/lib/wasm32-wasi-threads/libemnapi-napi-rs-mt.a +0 -0
  25. package/lib/wasm32-wasi-threads/libemnapi.a +0 -0
  26. package/lib/wasm32-wasip1/libemnapi-basic-mt.a +0 -0
  27. package/lib/wasm32-wasip1/libemnapi-basic.a +0 -0
  28. package/lib/wasm32-wasip1/libemnapi.a +0 -0
  29. package/lib/wasm32-wasip1-threads/libemnapi-basic-mt.a +0 -0
  30. package/lib/wasm32-wasip1-threads/libemnapi-basic-napi-rs-mt.a +0 -0
  31. package/lib/wasm32-wasip1-threads/libemnapi-basic.a +0 -0
  32. package/lib/wasm32-wasip1-threads/libemnapi-mt.a +0 -0
  33. package/lib/wasm32-wasip1-threads/libemnapi-napi-rs-mt.a +0 -0
  34. package/lib/wasm32-wasip1-threads/libemnapi.a +0 -0
  35. package/lib/wasm64-emscripten/libemnapi-basic.a +0 -0
  36. package/lib/wasm64-emscripten/libemnapi-mt.a +0 -0
  37. package/lib/wasm64-emscripten/libemnapi.a +0 -0
  38. package/package.json +1 -1
  39. package/src/emnapi_internal.h +7 -0
  40. package/src/threadsafe_function.c +4 -4
  41. package/src/wasi_wait.c +106 -0
package/CMakeLists.txt CHANGED
@@ -44,6 +44,7 @@ set(ENAPI_BASIC_SRC
44
44
  "${CMAKE_CURRENT_SOURCE_DIR}/src/node_api.c"
45
45
  "${CMAKE_CURRENT_SOURCE_DIR}/src/async_cleanup_hook.c"
46
46
  "${CMAKE_CURRENT_SOURCE_DIR}/src/async_context.c"
47
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/wasi_wait.c"
47
48
  )
48
49
  set(EMNAPI_THREADS_SRC
49
50
  "${CMAKE_CURRENT_SOURCE_DIR}/src/async_work.c"
@@ -70,6 +71,10 @@ set(EMNAPI_BASIC_TARGET_NAME "emnapi-basic")
70
71
  set(EMNAPI_BASIC_MT_TARGET_NAME "emnapi-basic-mt")
71
72
  set(EMNAPI_TARGET_NAME "emnapi")
72
73
  set(EMNAPI_MT_TARGET_NAME "emnapi-mt")
74
+
75
+ set(EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME "emnapi-basic-napi-rs-mt")
76
+ set(EMNAPI_NAPI_RS_MT_TARGET_NAME "emnapi-napi-rs-mt")
77
+
73
78
  set(DLMALLOC_TARGET_NAME "dlmalloc")
74
79
  set(DLMALLOC_MT_TARGET_NAME "dlmalloc-mt")
75
80
  set(EMMALLOC_TARGET_NAME "emmalloc")
@@ -155,6 +160,31 @@ else()
155
160
  set(EMNAPI_BUILD_BASIC_MT OFF)
156
161
  endif()
157
162
 
163
+ if(IS_WASM32_WASIP1_THREADS)
164
+ set(EMNAPI_BUILD_FOR_NAPI_RS ON)
165
+ else()
166
+ set(EMNAPI_BUILD_FOR_NAPI_RS OFF)
167
+ endif()
168
+
169
+ if(EMNAPI_BUILD_FOR_NAPI_RS)
170
+ add_library(${EMNAPI_NAPI_RS_MT_TARGET_NAME} STATIC ${EMNAPI_SRC} ${UV_SRC})
171
+ target_include_directories(${EMNAPI_NAPI_RS_MT_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
172
+ target_compile_definitions(${EMNAPI_NAPI_RS_MT_TARGET_NAME}
173
+ PUBLIC ${EMNAPI_DEFINES} "NAPI_EXTERN=__attribute__((__import_module__(\"env\")))"
174
+ )
175
+
176
+ add_library(${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME} STATIC
177
+ ${ENAPI_BASIC_SRC}
178
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_create.c"
179
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/thread/async_worker_init.S"
180
+ )
181
+ target_include_directories(${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
182
+ target_compile_definitions(${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME}
183
+ PUBLIC ${EMNAPI_DEFINES} "NAPI_EXTERN=__attribute__((__import_module__(\"env\")))"
184
+ PRIVATE "EMNAPI_DISABLE_UV"
185
+ )
186
+ endif()
187
+
158
188
  if(EMNAPI_BUILD_BASIC_MT)
159
189
  add_library(${EMNAPI_BASIC_MT_TARGET_NAME} STATIC
160
190
  ${ENAPI_BASIC_SRC}
@@ -222,6 +252,10 @@ if(LIB_ARCH)
222
252
  if(EMNAPI_BUILD_BASIC_MT)
223
253
  install(TARGETS ${EMNAPI_BASIC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
224
254
  endif()
255
+ if(EMNAPI_BUILD_FOR_NAPI_RS)
256
+ install(TARGETS ${EMNAPI_NAPI_RS_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
257
+ install(TARGETS ${EMNAPI_BASIC_NAPI_RS_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
258
+ endif()
225
259
  if(IS_WASM32)
226
260
  install(TARGETS ${DLMALLOC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
227
261
  install(TARGETS ${DLMALLOC_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
package/README.md CHANGED
@@ -816,8 +816,9 @@ Now emnapi has 3 implementations of async work and 2 implementations of TSFN:
816
816
  There are some limitations on browser about wasi-libc's pthread implementation, for example
817
817
  `pthread_mutex_lock` may call `__builtin_wasm_memory_atomic_wait32`(`memory.atomic.wait32`)
818
818
  which is disallowed in browser JS main thread. While Emscripten's pthread implementation
819
- has considered usage in browser. If you need to run your addon with multithreaded features on browser,
820
- we recommend you use Emscripten A & D, or bare wasm32 C & E.
819
+ has considered usage in browser. This issue can be solved by upgrading `wasi-sdk` to v26+
820
+ and emnapi v1.5.0+ then pass `--export=emnapi_thread_crashed` to the linker. If you need to
821
+ run your addon with multithreaded features, we recommend you use A & D or C & E.
821
822
 
822
823
  Note: For browsers, all the multithreaded features relying on Web Workers (Emscripten pthread also relying on Web Workers)
823
824
  require cross-origin isolation to enable `SharedArrayBuffer`. You can make a page cross-origin isolated
@@ -879,6 +880,7 @@ elseif(CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads")
879
880
  "-Wl,--export-if-defined=node_api_module_get_api_version_v1"
880
881
  "-Wl,--export=malloc"
881
882
  "-Wl,--export=free"
883
+ "-Wl,--export=emnapi_thread_crashed"
882
884
  "-Wl,--import-undefined"
883
885
  "-Wl,--export-table"
884
886
  )
package/common.gypi CHANGED
@@ -308,6 +308,7 @@
308
308
  'src/async_cleanup_hook.c',
309
309
  'src/async_context.c',
310
310
  'src/async_work.c',
311
+ 'src/wasi_wait.c',
311
312
  'src/threadsafe_function.c',
312
313
  'src/uv/uv-common.c',
313
314
  'src/uv/threadpool.c',
@@ -370,6 +371,16 @@
370
371
  ]
371
372
  },
372
373
  }],
374
+ ['OS == "wasi"', {
375
+ 'ldflags': [
376
+ '-Wl,--export=emnapi_thread_crashed',
377
+ ],
378
+ 'xcode_settings': {
379
+ 'OTHER_LDFLAGS': [
380
+ '-Wl,--export=emnapi_thread_crashed',
381
+ ],
382
+ },
383
+ }],
373
384
  ['OS != "wasi"', {
374
385
  'defines': [
375
386
  'PAGESIZE=65536'
@@ -61,10 +61,13 @@ function emnapiInit(options) {
61
61
  });
62
62
  }
63
63
  catch (err) {
64
+ if (err !== 'unwind') {
65
+ throw err;
66
+ }
67
+ }
68
+ finally {
64
69
  emnapiCtx.closeScope(envObject, scope);
65
- throw err;
66
70
  }
67
- emnapiCtx.closeScope(envObject, scope);
68
71
  emnapiModule.loaded = true;
69
72
  delete emnapiModule.envObject;
70
73
  return emnapiModule.exports;
@@ -75,7 +78,6 @@ function emnapiInit(options) {
75
78
  function __emnapi_async_work_pool_size() {
76
79
  return Math.abs(emnapiAsyncWorkPoolSize);
77
80
  }
78
- /* eslint-disable @typescript-eslint/indent */
79
81
  /**
80
82
  * @__sig ipiip
81
83
  */
@@ -180,6 +182,31 @@ function __emnapi_ctx_increase_waiting_request_counter() {
180
182
  function __emnapi_ctx_decrease_waiting_request_counter() {
181
183
  emnapiCtx.decreaseWaitingRequestCounter();
182
184
  }
185
+ /**
186
+ * @__sig i
187
+ */
188
+ function __emnapi_is_main_runtime_thread() {
189
+ return ENVIRONMENT_IS_PTHREAD ? 0 : 1;
190
+ }
191
+ /**
192
+ * @__sig i
193
+ */
194
+ function __emnapi_is_main_browser_thread() {
195
+ return (typeof window !== 'undefined' && typeof document !== 'undefined' && !ENVIRONMENT_IS_NODE) ? 1 : 0;
196
+ }
197
+ /**
198
+ * @__sig v
199
+ */
200
+ function __emnapi_unwind() {
201
+ // eslint-disable-next-line @typescript-eslint/no-throw-literal
202
+ throw 'unwind';
203
+ }
204
+ /**
205
+ * @__sig d
206
+ */
207
+ function __emnapi_get_now() {
208
+ return performance.timeOrigin + performance.now();
209
+ }
183
210
  function emnapiSetValueI64(result, numberValue) {
184
211
  var tempDouble;
185
212
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -190,6 +217,20 @@ function emnapiSetValueI64(result, numberValue) {
190
217
  {{{ makeSetValue('result', 0, 'tempI64[0]', 'i32') }}};
191
218
  {{{ makeSetValue('result', 4, 'tempI64[1]', 'i32') }}};
192
219
  }
220
+ /**
221
+ * @__deps $emnapiCtx
222
+ * @__sig p
223
+ */
224
+ function __emnapi_open_handle_scope() {
225
+ return emnapiCtx.openScope().id;
226
+ }
227
+ /**
228
+ * @__deps $emnapiCtx
229
+ * @__sig vp
230
+ */
231
+ function __emnapi_close_handle_scope(_scope) {
232
+ return emnapiCtx.closeScope();
233
+ }
193
234
  /* eslint-disable eqeqeq */
194
235
  /* eslint-disable @typescript-eslint/no-unused-vars */
195
236
  /* eslint-disable @typescript-eslint/indent */
@@ -6655,6 +6696,9 @@ function _napi_get_version(env, result) {
6655
6696
  _emnapi_callback_into_module: __emnapi_callback_into_module,
6656
6697
  _emnapi_callback_into_module__deps: ["$emnapiCtx"],
6657
6698
  _emnapi_callback_into_module__sig: "vipppi",
6699
+ _emnapi_close_handle_scope: __emnapi_close_handle_scope,
6700
+ _emnapi_close_handle_scope__deps: ["$emnapiCtx", "$emnapiCtx"],
6701
+ _emnapi_close_handle_scope__sig: "vp",
6658
6702
  _emnapi_ctx_decrease_waiting_request_counter: __emnapi_ctx_decrease_waiting_request_counter,
6659
6703
  _emnapi_ctx_decrease_waiting_request_counter__deps: ["$emnapiCtx"],
6660
6704
  _emnapi_ctx_decrease_waiting_request_counter__sig: "v",
@@ -6681,6 +6725,12 @@ function _napi_get_version(env, result) {
6681
6725
  _emnapi_get_last_error_info__sig: "vpppp",
6682
6726
  _emnapi_get_node_version: __emnapi_get_node_version,
6683
6727
  _emnapi_get_node_version__sig: "vppp",
6728
+ _emnapi_get_now: __emnapi_get_now,
6729
+ _emnapi_get_now__sig: "d",
6730
+ _emnapi_is_main_browser_thread: __emnapi_is_main_browser_thread,
6731
+ _emnapi_is_main_browser_thread__sig: "i",
6732
+ _emnapi_is_main_runtime_thread: __emnapi_is_main_runtime_thread,
6733
+ _emnapi_is_main_runtime_thread__sig: "i",
6684
6734
  _emnapi_node_emit_async_destroy: __emnapi_node_emit_async_destroy,
6685
6735
  _emnapi_node_emit_async_destroy__deps: ["$emnapiNodeBinding"],
6686
6736
  _emnapi_node_emit_async_destroy__sig: "vdd",
@@ -6690,12 +6740,17 @@ function _napi_get_version(env, result) {
6690
6740
  _emnapi_node_make_callback: __emnapi_node_make_callback,
6691
6741
  _emnapi_node_make_callback__deps: ["$emnapiNodeBinding", "$emnapiCtx"],
6692
6742
  _emnapi_node_make_callback__sig: "ipppppddp",
6743
+ _emnapi_open_handle_scope: __emnapi_open_handle_scope,
6744
+ _emnapi_open_handle_scope__deps: ["$emnapiCtx", "$emnapiCtx"],
6745
+ _emnapi_open_handle_scope__sig: "p",
6693
6746
  _emnapi_runtime_keepalive_pop: __emnapi_runtime_keepalive_pop,
6694
6747
  _emnapi_runtime_keepalive_pop__deps: ["$runtimeKeepalivePop"],
6695
6748
  _emnapi_runtime_keepalive_pop__sig: "v",
6696
6749
  _emnapi_runtime_keepalive_push: __emnapi_runtime_keepalive_push,
6697
6750
  _emnapi_runtime_keepalive_push__deps: ["$runtimeKeepalivePush"],
6698
6751
  _emnapi_runtime_keepalive_push__sig: "v",
6752
+ _emnapi_unwind: __emnapi_unwind,
6753
+ _emnapi_unwind__sig: "v",
6699
6754
  _emnapi_worker_unref: __emnapi_worker_unref,
6700
6755
  _emnapi_worker_unref__deps: ["$PThread"],
6701
6756
  _emnapi_worker_unref__sig: "vp",
package/emnapi.gyp CHANGED
@@ -55,6 +55,7 @@
55
55
  'src/node_api.c',
56
56
  'src/async_cleanup_hook.c',
57
57
  'src/async_context.c',
58
+ 'src/wasi_wait.c',
58
59
  ],
59
60
  'link_settings': {
60
61
  'target_conditions': [
@@ -88,6 +89,22 @@
88
89
  ]
89
90
  },
90
91
  }],
92
+ ['OS == "wasi"', {
93
+ 'link_settings': {
94
+ 'target_conditions': [
95
+ ['_type == "executable"', {
96
+ 'ldflags': [
97
+ '-Wl,--export=emnapi_thread_crashed',
98
+ ],
99
+ 'xcode_settings': {
100
+ 'OTHER_LDFLAGS': [
101
+ '-Wl,--export=emnapi_thread_crashed',
102
+ ],
103
+ },
104
+ }],
105
+ ]
106
+ },
107
+ }],
91
108
  ]
92
109
  },
93
110
  {
@@ -98,6 +115,7 @@
98
115
  'src/node_api.c',
99
116
  'src/async_cleanup_hook.c',
100
117
  'src/async_context.c',
118
+ 'src/wasi_wait.c',
101
119
 
102
120
  'src/uv/uv-common.c',
103
121
  'src/uv/threadpool.c',
@@ -6,8 +6,8 @@
6
6
  #include "emnapi_common.h"
7
7
 
8
8
  #define EMNAPI_MAJOR_VERSION 1
9
- #define EMNAPI_MINOR_VERSION 4
10
- #define EMNAPI_PATCH_VERSION 5
9
+ #define EMNAPI_MINOR_VERSION 5
10
+ #define EMNAPI_PATCH_VERSION 0
11
11
 
12
12
  typedef enum {
13
13
  emnapi_runtime,
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emnapi",
3
- "version": "1.4.5",
3
+ "version": "1.5.0",
4
4
  "description": "Node-API implementation for Emscripten",
5
5
  "main": "index.js",
6
6
  "gypfile": false,
@@ -98,11 +98,18 @@ EMNAPI_INTERNAL_EXTERN void _emnapi_runtime_keepalive_pop();
98
98
  #define EMNAPI_KEEPALIVE_POP _emnapi_runtime_keepalive_pop
99
99
  #endif
100
100
 
101
+ EMNAPI_INTERNAL_EXTERN napi_handle_scope _emnapi_open_handle_scope();
102
+ EMNAPI_INTERNAL_EXTERN void _emnapi_close_handle_scope(napi_handle_scope scope);
101
103
  EMNAPI_INTERNAL_EXTERN void _emnapi_env_ref(napi_env env);
102
104
  EMNAPI_INTERNAL_EXTERN void _emnapi_env_unref(napi_env env);
103
105
  EMNAPI_INTERNAL_EXTERN void _emnapi_ctx_increase_waiting_request_counter();
104
106
  EMNAPI_INTERNAL_EXTERN void _emnapi_ctx_decrease_waiting_request_counter();
105
107
 
108
+ EMNAPI_INTERNAL_EXTERN int _emnapi_is_main_browser_thread();
109
+ EMNAPI_INTERNAL_EXTERN int _emnapi_is_main_runtime_thread();
110
+ EMNAPI_INTERNAL_EXTERN double _emnapi_get_now();
111
+ EMNAPI_INTERNAL_EXTERN void _emnapi_unwind();
112
+
106
113
  #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
107
114
  #define EMNAPI_HAVE_THREADS 1
108
115
  #else
@@ -136,6 +136,8 @@ static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
136
136
  EMNAPI_ASSERT_CALL(napi_delete_reference(func->env, func->ref));
137
137
  }
138
138
 
139
+ EMNAPI_ASYNC_RESOURCE_DTOR(func->env, (emnapi_async_resource*) func);
140
+
139
141
  EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(func->env, _emnapi_tsfn_cleanup, func));
140
142
  _emnapi_env_unref(func->env);
141
143
  if (func->async_ref) {
@@ -144,7 +146,6 @@ static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
144
146
  func->async_ref = false;
145
147
  }
146
148
 
147
- EMNAPI_ASYNC_RESOURCE_DTOR(func->env, (emnapi_async_resource*) func);
148
149
  free(func);
149
150
  }
150
151
 
@@ -209,8 +210,7 @@ static napi_value _emnapi_tsfn_finalize_in_callback_scope(napi_env env, napi_cal
209
210
  }
210
211
 
211
212
  static void _emnapi_tsfn_finalize(napi_threadsafe_function func) {
212
- napi_handle_scope scope;
213
- EMNAPI_ASSERT_CALL(napi_open_handle_scope(func->env, &scope));
213
+ napi_handle_scope scope = _emnapi_open_handle_scope();
214
214
  if (func->finalize_cb) {
215
215
  if (emnapi_is_node_binding_available()) {
216
216
  napi_value resource, cb;
@@ -229,7 +229,7 @@ static void _emnapi_tsfn_finalize(napi_threadsafe_function func) {
229
229
  }
230
230
  }
231
231
  _emnapi_tsfn_empty_queue_and_delete(func);
232
- EMNAPI_ASSERT_CALL(napi_close_handle_scope(func->env, scope));
232
+ _emnapi_close_handle_scope(scope);
233
233
  }
234
234
 
235
235
  static void _emnapi_tsfn_do_finalize(uv_handle_t* data) {
@@ -0,0 +1,106 @@
1
+ #if defined(__wasi__)
2
+
3
+ #include <time.h>
4
+ #include <errno.h>
5
+ #include <pthread.h>
6
+ #include <stdio.h>
7
+ #include "emnapi_internal.h"
8
+
9
+ struct __pthread {
10
+ unsigned char _[32];
11
+ volatile int cancel;
12
+ volatile unsigned char canceldisable, cancelasync;
13
+ unsigned char tsd_used:1;
14
+ unsigned char dlerror_flag:1;
15
+ unsigned char __[68];
16
+ };
17
+
18
+ #define INFINITY __builtin_inff()
19
+
20
+ int __wasilibc_futex_wait_atomic_wait(volatile void *addr, int op, int val, int64_t max_wait_ns);
21
+
22
+ static _Atomic pthread_t crashed_thread_id = NULL;
23
+
24
+ __attribute__((visibility("default")))
25
+ void emnapi_thread_crashed() {
26
+ crashed_thread_id = pthread_self();
27
+ }
28
+
29
+ void _emnapi_yield() {
30
+ if (crashed_thread_id) {
31
+ _emnapi_runtime_keepalive_push();
32
+ _emnapi_unwind();
33
+ }
34
+ }
35
+
36
+ static int _emnapi_wait_main_browser_thread(int is_runtime_thread, volatile void *addr, int op, int val, double max_wait_ms) {
37
+ double now = _emnapi_get_now();
38
+ double end = now + max_wait_ms;
39
+
40
+ while (1) {
41
+ now = _emnapi_get_now();
42
+ if (now >= end) {
43
+ return -ETIMEDOUT;
44
+ }
45
+
46
+ if (is_runtime_thread) {
47
+ _emnapi_yield();
48
+ }
49
+
50
+ if (__c11_atomic_load((_Atomic int *)addr, __ATOMIC_SEQ_CST) != val) {
51
+ break;
52
+ }
53
+ }
54
+
55
+ return 0;
56
+ }
57
+
58
+ int _emnapi_wait(int is_runtime_thread, volatile void *addr, int op, int val, double max_wait_ms) {
59
+ if (is_runtime_thread) {
60
+ _emnapi_yield();
61
+ }
62
+
63
+ // https://github.com/WebAssembly/wasi-libc/blob/3f7eb4c7d6ede4dde3c4bffa6ed14e8d656fe93f/libc-top-half/musl/src/thread/wasm32/__wasilibc_busywait.c#L42
64
+ if (!_emnapi_is_main_browser_thread()) {
65
+ int64_t max_wait_ns = -1;
66
+ if (max_wait_ms != INFINITY) {
67
+ max_wait_ns = (int64_t)(max_wait_ms*1000*1000);
68
+ }
69
+ return __wasilibc_futex_wait_atomic_wait(addr, op, val, max_wait_ns);
70
+ }
71
+
72
+ return _emnapi_wait_main_browser_thread(is_runtime_thread, addr, op, val, max_wait_ms);
73
+ }
74
+
75
+ int __wasilibc_futex_wait_maybe_busy(volatile void *addr, int op, int val, int64_t max_wait_ns) {
76
+ // https://github.com/emscripten-core/emscripten/blob/89ce854a99238d04116a3d9b5afe241eec90c6c3/system/lib/libc/musl/src/thread/__timedwait.c#L60
77
+ int r = 0;
78
+ double msecsToSleep = max_wait_ns >= 0 ? (max_wait_ns / 1000000.0) : INFINITY;
79
+ int is_runtime_thread = _emnapi_is_main_runtime_thread();
80
+ double max_ms_slice_to_sleep = is_runtime_thread ? 1 : 100;
81
+
82
+ if (is_runtime_thread ||
83
+ pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE ||
84
+ pthread_self()->cancelasync) {
85
+ double sleepUntilTime = _emnapi_get_now() + msecsToSleep;
86
+ do {
87
+ if (pthread_self()->cancel) {
88
+ pthread_testcancel();
89
+ return ECANCELED;
90
+ }
91
+ msecsToSleep = sleepUntilTime - _emnapi_get_now();
92
+ if (msecsToSleep <= 0) {
93
+ r = ETIMEDOUT;
94
+ break;
95
+ }
96
+ if (msecsToSleep > max_ms_slice_to_sleep)
97
+ msecsToSleep = max_ms_slice_to_sleep;
98
+ r = -_emnapi_wait(is_runtime_thread, (void*)addr, op, val, msecsToSleep);
99
+ } while (r == ETIMEDOUT);
100
+ } else {
101
+ r = -_emnapi_wait(is_runtime_thread, (void*)addr, op, val, msecsToSleep);
102
+ }
103
+ return r;
104
+ }
105
+
106
+ #endif