emnapi 0.31.0 → 0.32.2

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
@@ -26,7 +26,19 @@ set(UV_SRC
26
26
  "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/unix/core.c"
27
27
  )
28
28
 
29
- set(EMNAPI_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/emnapi.c")
29
+ set(ENAPI_BASIC_SRC
30
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/js_native_api.c"
31
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/node_api.c"
32
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/emnapi.c"
33
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/async_cleanup_hook.c"
34
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/async_context.c"
35
+ )
36
+ set(EMNAPI_THREADS_SRC
37
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/async_work.c"
38
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/threadsafe_function.c"
39
+ )
40
+ set(EMNAPI_SRC ${ENAPI_BASIC_SRC} ${EMNAPI_THREADS_SRC})
41
+
30
42
  set(EMNAPI_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include")
31
43
 
32
44
  set(EMNAPI_JS_LIB "${CMAKE_CURRENT_SOURCE_DIR}/dist/library_napi.js")
@@ -37,6 +49,7 @@ else()
37
49
  set(EMNAPI_MT_CFLAGS "-pthread")
38
50
  endif()
39
51
 
52
+ set(EMNAPI_BASIC_TARGET_NAME "emnapi-basic")
40
53
  set(EMNAPI_TARGET_NAME "emnapi")
41
54
  set(EMNAPI_MT_TARGET_NAME "emnapi-mt")
42
55
  set(DLMALLOC_TARGET_NAME "dlmalloc")
@@ -82,6 +95,12 @@ if(IS_EMSCRIPTEN)
82
95
  target_link_options(${EMNAPI_TARGET_NAME} INTERFACE "--js-library=${EMNAPI_JS_LIB}")
83
96
  endif()
84
97
 
98
+ add_library(${EMNAPI_BASIC_TARGET_NAME} STATIC ${ENAPI_BASIC_SRC})
99
+ target_include_directories(${EMNAPI_BASIC_TARGET_NAME} PUBLIC ${EMNAPI_INCLUDE})
100
+ if(IS_EMSCRIPTEN)
101
+ target_link_options(${EMNAPI_BASIC_TARGET_NAME} INTERFACE "--js-library=${EMNAPI_JS_LIB}")
102
+ endif()
103
+
85
104
  if(IS_EMSCRIPTEN OR (CMAKE_C_COMPILER_TARGET STREQUAL "wasm32-wasi-threads"))
86
105
  set(EMNAPI_BUILD_MT ON)
87
106
  else()
@@ -118,6 +137,7 @@ endif()
118
137
  # endif()
119
138
  if(LIB_ARCH)
120
139
  install(TARGETS ${EMNAPI_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
140
+ install(TARGETS ${EMNAPI_BASIC_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
121
141
  if(EMNAPI_BUILD_MT)
122
142
  install(TARGETS ${EMNAPI_MT_TARGET_NAME} DESTINATION "lib/${LIB_ARCH}")
123
143
  endif()
@@ -150,6 +170,7 @@ install(FILES
150
170
  if(EMNAPI_INSTALL_SRC)
151
171
  install(FILES
152
172
  ${EMNAPI_SRC}
173
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/emnapi_common.h"
153
174
  DESTINATION "src/${PROJECT_NAME}")
154
175
  install(DIRECTORY
155
176
  ${CMAKE_CURRENT_SOURCE_DIR}/src/uv
package/README.md CHANGED
@@ -348,12 +348,13 @@ fetch('./hello.wasm').then(res => res.arrayBuffer()).then(wasmBuffer => {
348
348
  napi: napiModule.imports.napi,
349
349
  emnapi: napiModule.imports.emnapi
350
350
  })
351
- }).then(({ instance }) => {
352
- const binding = napiModule.init(
351
+ }).then(({ instance, module }) => {
352
+ const binding = napiModule.init({
353
353
  instance, // WebAssembly.Instance
354
- instance.exports.memory, // WebAssembly.Memory
355
- instance.exports.__indirect_function_table // WebAssembly.Table
356
- )
354
+ module, // WebAssembly.Module
355
+ memory: instance.exports.memory, // WebAssembly.Memory
356
+ table: instance.exports.__indirect_function_table // WebAssembly.Table
357
+ })
357
358
  // binding === napiModule.exports
358
359
  })
359
360
  </script>
@@ -383,13 +384,14 @@ WebAssembly.instantiate(require('fs').readFileSync('./hello.wasm'), {
383
384
  // clang
384
385
  napi: napiModule.imports.napi,
385
386
  emnapi: napiModule.imports.emnapi
386
- }).then(({ instance }) => {
387
+ }).then(({ instance, module }) => {
387
388
  wasi.initialize(instance)
388
- const binding = napiModule.init(
389
+ const binding = napiModule.init({
389
390
  instance,
390
- instance.exports.memory,
391
- instance.exports.__indirect_function_table
392
- )
391
+ module,
392
+ memory: instance.exports.memory,
393
+ table: instance.exports.__indirect_function_table
394
+ })
393
395
  // binding === napiModule.exports
394
396
  })
395
397
  ```
@@ -408,7 +410,7 @@ const napiModule = createNapiModule({
408
410
  })
409
411
 
410
412
  const fs = createFsFromVolume(Volume.from({ /* ... */ }))
411
- const wasi = WASI.createSync({ fs, /* ... */ })
413
+ const wasi = new WASI({ fs, /* ... */ })
412
414
 
413
415
  WebAssembly.instantiate(wasmBuffer, {
414
416
  wasi_snapshot_preview1: wasi.wasiImport,
@@ -421,13 +423,14 @@ WebAssembly.instantiate(wasmBuffer, {
421
423
  // clang
422
424
  napi: napiModule.imports.napi,
423
425
  emnapi: napiModule.imports.emnapi
424
- }).then(({ instance }) => {
426
+ }).then(({ instance, module }) => {
425
427
  wasi.initialize(instance)
426
- const binding = napiModule.init(
428
+ const binding = napiModule.init({
427
429
  instance,
428
- instance.exports.memory,
429
- instance.exports.__indirect_function_table
430
- )
430
+ module,
431
+ memory: instance.exports.memory,
432
+ table: instance.exports.__indirect_function_table
433
+ })
431
434
  // binding === napiModule.exports
432
435
  })
433
436
  ```
@@ -1,5 +1,205 @@
1
1
  {{{ ((DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.indexOf("$emnapiInit") === -1 ? DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push("$emnapiInit") : undefined), "") }}}
2
2
  {{{ ((EXPORTED_RUNTIME_METHODS.indexOf("emnapiInit") === -1 ? EXPORTED_RUNTIME_METHODS.push("emnapiInit") : undefined), "") }}}
3
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
4
+ function emnapiCreateIdGenerator() {
5
+ var obj = {
6
+ nextId: 1,
7
+ list: [],
8
+ generate: function () {
9
+ var id;
10
+ if (obj.list.length) {
11
+ id = obj.list.shift();
12
+ }
13
+ else {
14
+ id = obj.nextId;
15
+ obj.nextId++;
16
+ }
17
+ return id;
18
+ },
19
+ reuse: function (id) {
20
+ obj.list.push(id);
21
+ }
22
+ };
23
+ return obj;
24
+ }
25
+ var emnapiAsyncWork = {
26
+ idGen: {},
27
+ values: [undefined],
28
+ queued: new Set(),
29
+ pending: [],
30
+ init: function () {
31
+ emnapiAsyncWork.idGen = emnapiCreateIdGenerator();
32
+ emnapiAsyncWork.values = [undefined];
33
+ emnapiAsyncWork.queued = new Set();
34
+ emnapiAsyncWork.pending = [];
35
+ },
36
+ create: function (env, resource, resourceName, execute, complete, data) {
37
+ var asyncId = 0;
38
+ var triggerAsyncId = 0;
39
+ if (emnapiNodeBinding) {
40
+ var asyncContext = emnapiNodeBinding.node.emitAsyncInit(resource, resourceName, -1);
41
+ asyncId = asyncContext.asyncId;
42
+ triggerAsyncId = asyncContext.triggerAsyncId;
43
+ }
44
+ var id = emnapiAsyncWork.idGen.generate();
45
+ emnapiAsyncWork.values[id] = {
46
+ env: env,
47
+ id: id,
48
+ resource: resource,
49
+ resourceName: resourceName,
50
+ asyncId: asyncId,
51
+ triggerAsyncId: triggerAsyncId,
52
+ status: 0,
53
+ execute: execute,
54
+ complete: complete,
55
+ data: data
56
+ };
57
+ return id;
58
+ },
59
+ callComplete: function (work, status) {
60
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
61
+ var complete = work.complete;
62
+ var env = work.env;
63
+ var data = work.data;
64
+ var callback = function () {
65
+ var envObject = emnapiCtx.envStore.get(env);
66
+ var scope = emnapiCtx.openScope(envObject);
67
+ try {
68
+ envObject.callIntoModule(function () {
69
+ {{{ makeDynCall('vpip', 'complete') }}}(env, status, data);
70
+ });
71
+ }
72
+ finally {
73
+ emnapiCtx.closeScope(envObject, scope);
74
+ }
75
+ };
76
+ if (emnapiNodeBinding) {
77
+ emnapiNodeBinding.node.makeCallback(work.resource, callback, [], {
78
+ asyncId: work.asyncId,
79
+ triggerAsyncId: work.triggerAsyncId
80
+ });
81
+ }
82
+ else {
83
+ callback();
84
+ }
85
+ },
86
+ queue: function (id) {
87
+ var work = emnapiAsyncWork.values[id];
88
+ if (!work)
89
+ return;
90
+ if (work.status === 0) {
91
+ work.status = 1;
92
+ if (emnapiAsyncWork.queued.size >= 4) {
93
+ emnapiAsyncWork.pending.push(id);
94
+ return;
95
+ }
96
+ emnapiAsyncWork.queued.add(id);
97
+ var env_1 = work.env;
98
+ var data_1 = work.data;
99
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
100
+ var execute = work.execute;
101
+ work.status = 2;
102
+ emnapiCtx.feature.setImmediate(function () {
103
+ {{{ makeDynCall('vpp', 'execute') }}}(env_1, data_1);
104
+ emnapiAsyncWork.queued.delete(id);
105
+ work.status = 3;
106
+ emnapiAsyncWork.callComplete(work, 0 /* napi_status.napi_ok */);
107
+ if (emnapiAsyncWork.pending.length > 0) {
108
+ var nextWorkId = emnapiAsyncWork.pending.shift();
109
+ emnapiAsyncWork.values[nextWorkId].status = 0;
110
+ emnapiAsyncWork.queue(nextWorkId);
111
+ }
112
+ });
113
+ }
114
+ },
115
+ cancel: function (id) {
116
+ var index = emnapiAsyncWork.pending.indexOf(id);
117
+ if (index !== -1) {
118
+ var work = emnapiAsyncWork.values[id];
119
+ if (work && (work.status === 1)) {
120
+ work.status = 4;
121
+ emnapiAsyncWork.pending.splice(index, 1);
122
+ emnapiAsyncWork.callComplete(work, 11 /* napi_status.napi_cancelled */);
123
+ return 0 /* napi_status.napi_ok */;
124
+ }
125
+ else {
126
+ return 9 /* napi_status.napi_generic_failure */;
127
+ }
128
+ }
129
+ return 9 /* napi_status.napi_generic_failure */;
130
+ },
131
+ remove: function (id) {
132
+ var work = emnapiAsyncWork.values[id];
133
+ if (!work)
134
+ return;
135
+ if (emnapiNodeBinding) {
136
+ emnapiNodeBinding.node.emitAsyncDestroy({
137
+ asyncId: work.asyncId,
138
+ triggerAsyncId: work.triggerAsyncId
139
+ });
140
+ }
141
+ emnapiAsyncWork.values[id] = undefined;
142
+ emnapiAsyncWork.idGen.reuse(id);
143
+ }
144
+ };
145
+ function _napi_create_async_work(env, resource, resource_name, execute, complete, data, result) {
146
+ if (env == 0)
147
+ return 1 /* napi_status.napi_invalid_arg */;
148
+ var envObject = emnapiCtx.envStore.get(env);
149
+ if (execute == 0)
150
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
151
+ if (result == 0)
152
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
153
+ var resourceObject;
154
+ if (resource) {
155
+ resourceObject = Object(emnapiCtx.handleStore.get(resource).value);
156
+ }
157
+ else {
158
+ resourceObject = {};
159
+ }
160
+ if (resource_name == 0)
161
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
162
+ var resourceName = String(emnapiCtx.handleStore.get(resource_name).value);
163
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
164
+ var id = emnapiAsyncWork.create(env, resourceObject, resourceName, execute, complete, data);
165
+ {{{ makeSetValue('result', 0, 'id', '*') }}};
166
+ return envObject.clearLastError();
167
+ }
168
+ function _napi_delete_async_work(env, work) {
169
+ if (env == 0)
170
+ return 1 /* napi_status.napi_invalid_arg */;
171
+ var envObject = emnapiCtx.envStore.get(env);
172
+ if (work == 0)
173
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
174
+ emnapiAsyncWork.remove(work);
175
+ return envObject.clearLastError();
176
+ }
177
+ function _napi_queue_async_work(env, work) {
178
+ if (env == 0)
179
+ return 1 /* napi_status.napi_invalid_arg */;
180
+ var envObject = emnapiCtx.envStore.get(env);
181
+ if (work == 0)
182
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
183
+ emnapiAsyncWork.queue(work);
184
+ return envObject.clearLastError();
185
+ }
186
+ function _napi_cancel_async_work(env, work) {
187
+ if (env == 0)
188
+ return 1 /* napi_status.napi_invalid_arg */;
189
+ var envObject = emnapiCtx.envStore.get(env);
190
+ if (work == 0)
191
+ return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
192
+ var status = emnapiAsyncWork.cancel(work);
193
+ if (status === 0 /* napi_status.napi_ok */)
194
+ return envObject.clearLastError();
195
+ return envObject.setLastError(status);
196
+ }
197
+ emnapiImplementHelper('$emnapiCreateIdGenerator', undefined, emnapiCreateIdGenerator, []);
198
+ emnapiDefineVar('$emnapiAsyncWork', emnapiAsyncWork, ['$emnapiCreateIdGenerator'], 'emnapiAsyncWork.init();');
199
+ emnapiImplement('napi_create_async_work', 'ippppppp', _napi_create_async_work, ['$emnapiAsyncWork']);
200
+ emnapiImplement('napi_delete_async_work', 'ipp', _napi_delete_async_work, ['$emnapiAsyncWork']);
201
+ emnapiImplement('napi_queue_async_work', 'ipp', _napi_queue_async_work, ['$emnapiAsyncWork']);
202
+ emnapiImplement('napi_cancel_async_work', 'ipp', _napi_cancel_async_work, ['$emnapiAsyncWork']);
3
203
  function _emnapi_create_memory_view(env, typedarray_type, external_data, byte_length, finalize_cb, finalize_hint, result
4
204
  // @ts-expect-error
5
205
  ) {
@@ -826,10 +1026,18 @@ function emnapiCreateFunction(envObject, utf8name, length, cb, data) {
826
1026
  }
827
1027
  #if DYNAMIC_EXECUTION
828
1028
  if (emnapiCtx.feature.supportNewFunction) {
829
- f = (new Function('_', 'return function ' + functionName + '(){' +
830
- '"use strict";' +
831
- 'return _.apply(this,arguments);' +
832
- '};'))(makeFunction());
1029
+ var _ = makeFunction();
1030
+ try {
1031
+ f = (new Function('_', 'return function ' + functionName + '(){' +
1032
+ '"use strict";' +
1033
+ 'return _.apply(this,arguments);' +
1034
+ '};'))(_);
1035
+ }
1036
+ catch (_err) {
1037
+ f = makeFunction();
1038
+ if (emnapiCtx.feature.canSetFunctionName)
1039
+ Object.defineProperty(f, 'name', { value: functionName });
1040
+ }
833
1041
  }
834
1042
  else {
835
1043
  f = makeFunction();
@@ -2180,7 +2388,7 @@ function napi_define_properties(env, object, property_count, properties
2180
2388
  var value_2 = {{{ makeGetValue("propPtr", POINTER_SIZE * 5, "*") }}};
2181
2389
  attributes = {{{ makeGetValue("propPtr", POINTER_SIZE * 6, POINTER_WASM_TYPE) }}};
2182
2390
  {{{ from64("attributes") }}};
2183
- var data_1 = {{{ makeGetValue("propPtr", POINTER_SIZE * 7, "*") }}};
2391
+ var data_2 = {{{ makeGetValue("propPtr", POINTER_SIZE * 7, "*") }}};
2184
2392
  if (utf8Name_1) {
2185
2393
  propertyName_1 = UTF8ToString(utf8Name_1);
2186
2394
  }
@@ -2193,7 +2401,7 @@ function napi_define_properties(env, object, property_count, properties
2193
2401
  return envObject_32.setLastError(4 /* napi_status.napi_name_expected */);
2194
2402
  }
2195
2403
  }
2196
- emnapiDefineProperty(envObject_32, maybeObject_1, propertyName_1, method_1, getter_1, setter_1, value_2, attributes, data_1);
2404
+ emnapiDefineProperty(envObject_32, maybeObject_1, propertyName_1, method_1, getter_1, setter_1, value_2, attributes, data_2);
2197
2405
  }
2198
2406
  return 0 /* napi_status.napi_ok */;
2199
2407
  }
@@ -2840,7 +3048,7 @@ function napi_define_class(env, utf8name, length, constructor, callback_data, pr
2840
3048
  var value_3 = {{{ makeGetValue("propPtr", POINTER_SIZE * 5, "*") }}};
2841
3049
  attributes = {{{ makeGetValue("propPtr", POINTER_SIZE * 6, POINTER_WASM_TYPE) }}};
2842
3050
  {{{ from64("attributes") }}};
2843
- var data_2 = {{{ makeGetValue("propPtr", POINTER_SIZE * 7, "*") }}};
3051
+ var data_3 = {{{ makeGetValue("propPtr", POINTER_SIZE * 7, "*") }}};
2844
3052
  if (utf8Name_2) {
2845
3053
  propertyName_2 = UTF8ToString(utf8Name_2);
2846
3054
  }
@@ -2854,10 +3062,10 @@ function napi_define_class(env, utf8name, length, constructor, callback_data, pr
2854
3062
  }
2855
3063
  }
2856
3064
  if ((attributes & 1024 /* napi_property_attributes.napi_static */) !== 0) {
2857
- emnapiDefineProperty(envObject_43, F_1, propertyName_2, method_2, getter_2, setter_2, value_3, attributes, data_2);
3065
+ emnapiDefineProperty(envObject_43, F_1, propertyName_2, method_2, getter_2, setter_2, value_3, attributes, data_3);
2858
3066
  continue;
2859
3067
  }
2860
- emnapiDefineProperty(envObject_43, F_1.prototype, propertyName_2, method_2, getter_2, setter_2, value_3, attributes, data_2);
3068
+ emnapiDefineProperty(envObject_43, F_1.prototype, propertyName_2, method_2, getter_2, setter_2, value_3, attributes, data_3);
2861
3069
  }
2862
3070
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2863
3071
  var valueHandle_2 = emnapiCtx.addToCurrentScope(F_1);
package/index.js CHANGED
@@ -7,7 +7,13 @@ const include = path.join(__dirname, 'include')
7
7
  const includeDir = path.relative(process.cwd(), include)
8
8
  const jsLibrary = path.join(__dirname, './dist/library_napi.js')
9
9
  const sources = [
10
+ path.join(__dirname, './src/js_native_api.c'),
11
+ path.join(__dirname, './src/node_api.c'),
10
12
  path.join(__dirname, './src/emnapi.c'),
13
+ path.join(__dirname, './src/async_cleanup_hook.c'),
14
+ path.join(__dirname, './src/async_context.c'),
15
+ path.join(__dirname, './src/async_work.c'),
16
+ path.join(__dirname, './src/threadsafe_function.c'),
11
17
  path.join(__dirname, './src/uv/uv-common.c'),
12
18
  path.join(__dirname, './src/uv/threadpool.c'),
13
19
  path.join(__dirname, './src/uv/unix/loop.c'),
Binary file
Binary file
Binary file
@@ -1,5 +1,5 @@
1
- emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.29 (43074846f216abad2a1c35b5a631f2a9481d9e07)
2
- clang version 16.0.0 (https://github.com/llvm/llvm-project 947d529e4194e0567cfbbea99127066f76c87269)
1
+ emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.32 (eab98adf462c39f3c31d348331c4830bcaa36949)
2
+ clang version 17.0.0 (https://github.com/llvm/llvm-project df82394e7a2d06506718cafa347bf7827c79fc4f)
3
3
  Target: wasm32-unknown-emscripten
4
4
  Thread model: posix
5
5
  InstalledDir: /home/runner/work/emnapi/emnapi/emsdk-cache/emsdk-main/upstream/bin
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emnapi",
3
- "version": "0.31.0",
3
+ "version": "0.32.2",
4
4
  "description": "Node-API implementation for Emscripten",
5
5
  "main": "index.js",
6
6
  "devDependencies": {
@@ -0,0 +1,126 @@
1
+ #include "emnapi_common.h"
2
+ #include "node_api.h"
3
+
4
+ EXTERN_C_START
5
+
6
+ typedef void (*async_cleanup_hook)(void* arg, void(*)(void*), void*);
7
+
8
+ struct async_cleanup_hook_info {
9
+ napi_env env;
10
+ async_cleanup_hook fun;
11
+ void* arg;
12
+ bool started;
13
+ };
14
+
15
+ struct napi_async_cleanup_hook_handle__ {
16
+ struct async_cleanup_hook_info* handle_;
17
+ napi_env env_;
18
+ napi_async_cleanup_hook user_hook_;
19
+ void* user_data_;
20
+ void (*done_cb_)(void*);
21
+ void* done_data_;
22
+ };
23
+
24
+ static void _emnapi_ach_handle_hook(void* data, void (*done_cb)(void*), void* done_data) {
25
+ napi_async_cleanup_hook_handle handle =
26
+ (napi_async_cleanup_hook_handle) (data);
27
+ handle->done_cb_ = done_cb;
28
+ handle->done_data_ = done_data;
29
+ handle->user_hook_(handle, handle->user_data_);
30
+ }
31
+
32
+ static void _emnapi_finish_async_cleanup_hook(void* arg) {
33
+ // struct async_cleanup_hook_info* info = (struct async_cleanup_hook_info*) (arg);
34
+ EMNAPI_KEEPALIVE_POP();
35
+ _emnapi_ctx_decrease_waiting_request_counter();
36
+ }
37
+
38
+ static void _emnapi_run_async_cleanup_hook(void* arg) {
39
+ struct async_cleanup_hook_info* info = (struct async_cleanup_hook_info*) (arg);
40
+ EMNAPI_KEEPALIVE_PUSH();
41
+ _emnapi_ctx_increase_waiting_request_counter();
42
+ info->started = true;
43
+ info->fun(info->arg, _emnapi_finish_async_cleanup_hook, info);
44
+ }
45
+
46
+ static struct async_cleanup_hook_info*
47
+ _emnapi_add_async_environment_cleanup_hook(napi_env env,
48
+ async_cleanup_hook fun,
49
+ void* arg) {
50
+ struct async_cleanup_hook_info* info =
51
+ (struct async_cleanup_hook_info*) malloc(sizeof(struct async_cleanup_hook_info));
52
+ info->env = env;
53
+ info->fun = fun;
54
+ info->arg = arg;
55
+ info->started = false;
56
+
57
+ EMNAPI_ASSERT_CALL(napi_add_env_cleanup_hook(env, _emnapi_run_async_cleanup_hook, info));
58
+
59
+ return info;
60
+ }
61
+
62
+ static void _emnapi_remove_async_environment_cleanup_hook(
63
+ struct async_cleanup_hook_info* info) {
64
+ if (info->started) return;
65
+ EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(info->env, _emnapi_run_async_cleanup_hook, info));
66
+ }
67
+
68
+ static napi_async_cleanup_hook_handle
69
+ _emnapi_ach_handle_create(napi_env env,
70
+ napi_async_cleanup_hook user_hook,
71
+ void* user_data) {
72
+ napi_async_cleanup_hook_handle handle =
73
+ (napi_async_cleanup_hook_handle) calloc(1, sizeof(struct napi_async_cleanup_hook_handle__));
74
+ handle->env_ = env;
75
+ handle->user_hook_ = user_hook;
76
+ handle->user_data_ = user_data;
77
+ handle->handle_ = _emnapi_add_async_environment_cleanup_hook(env, _emnapi_ach_handle_hook, handle);
78
+ _emnapi_env_ref(env);
79
+
80
+ return handle;
81
+ }
82
+
83
+ EMNAPI_INTERNAL_EXTERN void _emnapi_set_immediate(void (*callback)(void*), void* data);
84
+
85
+ static void _emnapi_ach_handle_env_unref(void* arg) {
86
+ napi_env env = (napi_env) arg;
87
+ _emnapi_env_unref(env);
88
+ }
89
+
90
+ static void
91
+ _emnapi_ach_handle_delete(napi_async_cleanup_hook_handle handle) {
92
+ _emnapi_remove_async_environment_cleanup_hook(handle->handle_);
93
+ if (handle->done_cb_ != NULL) handle->done_cb_(handle->done_data_);
94
+
95
+ _emnapi_set_immediate(_emnapi_ach_handle_env_unref, handle->env_);
96
+
97
+ free(handle->handle_);
98
+ free(handle);
99
+ }
100
+
101
+ napi_status
102
+ napi_add_async_cleanup_hook(napi_env env,
103
+ napi_async_cleanup_hook hook,
104
+ void* arg,
105
+ napi_async_cleanup_hook_handle* remove_handle) {
106
+ CHECK_ENV(env);
107
+ CHECK_ARG(env, hook);
108
+
109
+ napi_async_cleanup_hook_handle handle =
110
+ _emnapi_ach_handle_create(env, hook, arg);
111
+
112
+ if (remove_handle != NULL) *remove_handle = handle;
113
+
114
+ return napi_clear_last_error(env);
115
+ }
116
+
117
+ napi_status
118
+ napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) {
119
+ if (remove_handle == NULL) return napi_invalid_arg;
120
+
121
+ _emnapi_ach_handle_delete(remove_handle);
122
+
123
+ return napi_ok;
124
+ }
125
+
126
+ EXTERN_C_END
@@ -0,0 +1,53 @@
1
+ #include <node_api.h>
2
+ #include "emnapi_common.h"
3
+
4
+ EXTERN_C_START
5
+
6
+ struct napi_async_context__ {
7
+ int32_t low;
8
+ int32_t high;
9
+ };
10
+
11
+ EMNAPI_INTERNAL_EXTERN napi_status
12
+ _emnapi_async_init_js(napi_value async_resource,
13
+ napi_value async_resource_name,
14
+ napi_async_context result);
15
+ EMNAPI_INTERNAL_EXTERN napi_status
16
+ _emnapi_async_destroy_js(napi_async_context async_context);
17
+
18
+ napi_status
19
+ napi_async_init(napi_env env,
20
+ napi_value async_resource,
21
+ napi_value async_resource_name,
22
+ napi_async_context* result) {
23
+ CHECK_ENV(env);
24
+ CHECK_ARG(env, async_resource_name);
25
+ CHECK_ARG(env, result);
26
+
27
+ napi_async_context ret = (napi_async_context) malloc(sizeof(struct napi_async_context__));
28
+
29
+ napi_status status = _emnapi_async_init_js(async_resource, async_resource_name, ret);
30
+ if (status != napi_ok) {
31
+ free(ret);
32
+ return napi_set_last_error(env, status, 0, NULL);
33
+ }
34
+
35
+ *result = ret;
36
+ return napi_clear_last_error(env);
37
+ }
38
+
39
+ napi_status napi_async_destroy(napi_env env,
40
+ napi_async_context async_context) {
41
+ CHECK_ENV(env);
42
+ CHECK_ARG(env, async_context);
43
+
44
+ napi_status status = _emnapi_async_destroy_js(async_context);
45
+ if (status != napi_ok) {
46
+ return napi_set_last_error(env, status, 0, NULL);
47
+ }
48
+ free(async_context);
49
+
50
+ return napi_clear_last_error(env);
51
+ }
52
+
53
+ EXTERN_C_END