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/src/emnapi.c CHANGED
@@ -1,223 +1,7 @@
1
- #if defined(__EMSCRIPTEN__) || defined(__wasi__)
2
- #include <assert.h>
3
- #include <stdlib.h>
4
- #else
5
- #include <stddef.h>
6
- void* malloc(size_t size);
7
- void* calloc(size_t count, size_t size);
8
- void free(void* p);
9
- #endif
10
-
11
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
12
- #include <pthread.h>
13
-
14
- #include <errno.h>
15
- #include "uv.h"
16
- #endif
17
-
18
- #ifdef __EMSCRIPTEN__
19
- #include <emscripten.h>
20
- #include <emscripten/heap.h>
21
-
22
- #if __EMSCRIPTEN_major__ * 10000 + __EMSCRIPTEN_minor__ * 100 + __EMSCRIPTEN_tiny__ >= 30114 // NOLINT
23
- #include <emscripten/eventloop.h>
24
- #endif
25
- #endif
26
-
27
- #include "emnapi.h"
28
- #include "node_api.h"
29
-
30
- #if NAPI_VERSION >= 4 && (defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT))
31
- #include <stdatomic.h>
32
- #include "uv/queue.h"
33
- #endif
34
-
35
- #ifdef NDEBUG
36
- #define EMNAPI_ASSERT_CALL(the_call) (the_call)
37
- #else
38
- #if defined(__EMSCRIPTEN__) || defined(__wasi__)
39
- #define EMNAPI_ASSERT_CALL(the_call) (assert(napi_ok == (the_call)))
40
- #else
41
- #define EMNAPI_ASSERT_CALL(the_call) (the_call)
42
- #endif
43
- #endif
44
-
45
- #define CHECK_ENV(env) \
46
- do { \
47
- if ((env) == NULL) { \
48
- return napi_invalid_arg; \
49
- } \
50
- } while (0)
51
-
52
- #define RETURN_STATUS_IF_FALSE(env, condition, status) \
53
- do { \
54
- if (!(condition)) { \
55
- return napi_set_last_error((env), (status), 0, NULL); \
56
- } \
57
- } while (0)
58
-
59
- #define CHECK_ARG(env, arg) \
60
- RETURN_STATUS_IF_FALSE((env), ((arg) != NULL), napi_invalid_arg)
61
-
62
- #define CHECK(expr) \
63
- do { \
64
- if (!(expr)) { \
65
- __builtin_trap(); \
66
- } \
67
- } while (0)
68
-
69
- #define CHECK_NOT_NULL(val) CHECK((val) != NULL)
70
-
71
- #define CHECK_EQ(a, b) CHECK((a) == (b))
72
- #define CHECK_LE(a, b) CHECK((a) <= (b))
1
+ #include "emnapi_common.h"
73
2
 
74
3
  EXTERN_C_START
75
4
 
76
- EMNAPI_INTERNAL_EXTERN napi_status napi_set_last_error(napi_env env,
77
- napi_status error_code,
78
- uint32_t engine_error_code,
79
- void* engine_reserved);
80
- EMNAPI_INTERNAL_EXTERN napi_status napi_clear_last_error(napi_env env);
81
-
82
- #ifdef __EMSCRIPTEN__
83
- #if __EMSCRIPTEN_major__ * 10000 + __EMSCRIPTEN_minor__ * 100 + __EMSCRIPTEN_tiny__ >= 30114 // NOLINT
84
- #define EMNAPI_KEEPALIVE_PUSH emscripten_runtime_keepalive_push
85
- #define EMNAPI_KEEPALIVE_POP emscripten_runtime_keepalive_pop
86
- #else
87
-
88
- EMNAPI_INTERNAL_EXTERN void _emnapi_runtime_keepalive_push();
89
- EMNAPI_INTERNAL_EXTERN void _emnapi_runtime_keepalive_pop();
90
-
91
- #define EMNAPI_KEEPALIVE_PUSH _emnapi_runtime_keepalive_push
92
- #define EMNAPI_KEEPALIVE_POP _emnapi_runtime_keepalive_pop
93
- #endif
94
- #else
95
- EMNAPI_INTERNAL_EXTERN void _emnapi_runtime_keepalive_push();
96
- EMNAPI_INTERNAL_EXTERN void _emnapi_runtime_keepalive_pop();
97
-
98
- #define EMNAPI_KEEPALIVE_PUSH _emnapi_runtime_keepalive_push
99
- #define EMNAPI_KEEPALIVE_POP _emnapi_runtime_keepalive_pop
100
- #endif
101
-
102
- const char* emnapi_error_messages[] = {
103
- NULL,
104
- "Invalid argument",
105
- "An object was expected",
106
- "A string was expected",
107
- "A string or symbol was expected",
108
- "A function was expected",
109
- "A number was expected",
110
- "A boolean was expected",
111
- "An array was expected",
112
- "Unknown failure",
113
- "An exception is pending",
114
- "The async work item was cancelled",
115
- "napi_escape_handle already called on scope",
116
- "Invalid handle scope usage",
117
- "Invalid callback scope usage",
118
- "Thread-safe function queue is full",
119
- "Thread-safe function handle is closing",
120
- "A bigint was expected",
121
- "A date was expected",
122
- "An arraybuffer was expected",
123
- "A detachable arraybuffer was expected",
124
- "Main thread would deadlock",
125
- "External buffers are not allowed"
126
- };
127
-
128
- EMNAPI_INTERNAL_EXTERN void _emnapi_get_last_error_info(napi_env env,
129
- napi_status* error_code,
130
- uint32_t* engine_error_code,
131
- void** engine_reserved);
132
-
133
- napi_status napi_get_last_error_info(
134
- napi_env env, const napi_extended_error_info** result) {
135
- static napi_extended_error_info last_error;
136
- CHECK_ENV(env);
137
- CHECK_ARG(env, result);
138
-
139
- const int last_status = napi_no_external_buffers_allowed;
140
-
141
- _Static_assert((sizeof(emnapi_error_messages) / sizeof(const char*)) == napi_no_external_buffers_allowed + 1,
142
- "Count of error messages must match count of error values");
143
-
144
- _emnapi_get_last_error_info(env,
145
- &last_error.error_code,
146
- &last_error.engine_error_code,
147
- &last_error.engine_reserved);
148
-
149
- CHECK_LE(last_error.error_code, last_status);
150
-
151
- last_error.error_message = emnapi_error_messages[last_error.error_code];
152
-
153
- if (last_error.error_code == napi_ok) {
154
- napi_clear_last_error(env);
155
- last_error.engine_error_code = 0;
156
- last_error.engine_reserved = NULL;
157
- }
158
- *result = &last_error;
159
- return napi_ok;
160
- }
161
-
162
- #define PAGESIZE 65536
163
-
164
- napi_status napi_adjust_external_memory(napi_env env,
165
- int64_t change_in_bytes,
166
- int64_t* adjusted_value) {
167
- CHECK_ENV(env);
168
- CHECK_ARG(env, adjusted_value);
169
-
170
- if (change_in_bytes < 0) {
171
- return napi_set_last_error(env, napi_invalid_arg, 0, NULL);
172
- }
173
-
174
- size_t old_size = __builtin_wasm_memory_size(0) << 16;
175
- size_t new_size = old_size + (size_t) change_in_bytes;
176
- #ifdef __EMSCRIPTEN__
177
- if (!emscripten_resize_heap(new_size)) {
178
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
179
- }
180
- #else
181
- new_size = new_size + (PAGESIZE - new_size % PAGESIZE) % PAGESIZE;
182
- if (-1 == __builtin_wasm_memory_grow(0, (new_size - old_size + 65535) >> 16)) {
183
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
184
- }
185
- #endif
186
-
187
- *adjusted_value = (int64_t) (__builtin_wasm_memory_size(0) << 16);
188
-
189
- return napi_clear_last_error(env);
190
- }
191
-
192
- napi_status napi_get_version(napi_env env, uint32_t* result) {
193
- CHECK_ENV(env);
194
- CHECK_ARG(env, result);
195
- *result = NAPI_VERSION;
196
- return napi_clear_last_error(env);
197
- }
198
-
199
- EMNAPI_INTERNAL_EXTERN void _emnapi_get_node_version(uint32_t* major,
200
- uint32_t* minor,
201
- uint32_t* patch);
202
-
203
- napi_status
204
- napi_get_node_version(napi_env env,
205
- const napi_node_version** version) {
206
- CHECK_ENV(env);
207
- CHECK_ARG(env, version);
208
- static napi_node_version node_version = {
209
- 0,
210
- 0,
211
- 0,
212
- "node"
213
- };
214
- _emnapi_get_node_version(&node_version.major,
215
- &node_version.minor,
216
- &node_version.patch);
217
- *version = &node_version;
218
- return napi_clear_last_error(env);
219
- }
220
-
221
5
  #ifdef __EMSCRIPTEN__
222
6
  napi_status
223
7
  emnapi_get_emscripten_version(napi_env env,
@@ -234,1111 +18,4 @@ emnapi_get_emscripten_version(napi_env env,
234
18
  }
235
19
  #endif
236
20
 
237
- napi_status napi_get_uv_event_loop(napi_env env,
238
- struct uv_loop_s** loop) {
239
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
240
- CHECK_ENV(env);
241
- CHECK_ARG(env, loop);
242
- // Though this is fake libuv loop
243
- *loop = uv_default_loop();
244
- return napi_clear_last_error(env);
245
- #else
246
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
247
- #endif
248
- }
249
-
250
- EMNAPI_INTERNAL_EXTERN int _emnapi_get_filename(char* buf, int len);
251
-
252
- napi_status node_api_get_module_file_name(napi_env env,
253
- const char** result) {
254
- CHECK_ENV(env);
255
- CHECK_ARG(env, result);
256
-
257
- static char* filename = NULL;
258
- static const char* empty_string = "";
259
-
260
- if (filename != NULL) {
261
- free(filename);
262
- filename = NULL;
263
- }
264
-
265
- int len = _emnapi_get_filename(NULL, 0);
266
- if (len == 0) {
267
- *result = empty_string;
268
- } else {
269
- filename = (char*) malloc(len + 1);
270
- len = _emnapi_get_filename(filename, len + 1);
271
- *(filename + len) = '\0';
272
- *result = filename;
273
- }
274
-
275
- return napi_clear_last_error(env);
276
- }
277
-
278
- EMNAPI_INTERNAL_EXTERN void _emnapi_env_ref(napi_env env);
279
- EMNAPI_INTERNAL_EXTERN void _emnapi_env_unref(napi_env env);
280
- EMNAPI_INTERNAL_EXTERN void _emnapi_ctx_increase_waiting_request_counter();
281
- EMNAPI_INTERNAL_EXTERN void _emnapi_ctx_decrease_waiting_request_counter();
282
-
283
- struct napi_async_context__ {
284
- int32_t low;
285
- int32_t high;
286
- };
287
-
288
- EMNAPI_INTERNAL_EXTERN napi_status
289
- _emnapi_async_init_js(napi_value async_resource,
290
- napi_value async_resource_name,
291
- napi_async_context result);
292
- EMNAPI_INTERNAL_EXTERN napi_status
293
- _emnapi_async_destroy_js(napi_async_context async_context);
294
-
295
- napi_status
296
- napi_async_init(napi_env env,
297
- napi_value async_resource,
298
- napi_value async_resource_name,
299
- napi_async_context* result) {
300
- CHECK_ENV(env);
301
- CHECK_ARG(env, async_resource_name);
302
- CHECK_ARG(env, result);
303
-
304
- napi_async_context ret = (napi_async_context) malloc(sizeof(struct napi_async_context__));
305
-
306
- napi_status status = _emnapi_async_init_js(async_resource, async_resource_name, ret);
307
- if (status != napi_ok) {
308
- free(ret);
309
- return napi_set_last_error(env, status, 0, NULL);
310
- }
311
-
312
- *result = ret;
313
- return napi_clear_last_error(env);
314
- }
315
-
316
- napi_status napi_async_destroy(napi_env env,
317
- napi_async_context async_context) {
318
- CHECK_ENV(env);
319
- CHECK_ARG(env, async_context);
320
-
321
- napi_status status = _emnapi_async_destroy_js(async_context);
322
- if (status != napi_ok) {
323
- return napi_set_last_error(env, status, 0, NULL);
324
- }
325
- free(async_context);
326
-
327
- return napi_clear_last_error(env);
328
- }
329
-
330
- ////////////////////////////////////////////////////////////////////////////////
331
- // Async work implementation
332
- ////////////////////////////////////////////////////////////////////////////////
333
-
334
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
335
-
336
- #define container_of(ptr, type, member) \
337
- ((type *) ((char *) (ptr) - offsetof(type, member)))
338
-
339
- typedef void (*_emnapi_call_into_module_callback)(napi_env env, void* args);
340
- EMNAPI_INTERNAL_EXTERN void _emnapi_call_into_module(napi_env env, _emnapi_call_into_module_callback callback, void* args, int close_scope_if_throw);
341
-
342
- typedef double async_id;
343
- typedef struct async_context {
344
- async_id async_id;
345
- async_id trigger_async_id;
346
- } async_context;
347
-
348
- // call node::EmitAsyncInit
349
- EMNAPI_INTERNAL_EXTERN void _emnapi_node_emit_async_init(napi_value async_resource,
350
- napi_value async_resource_name,
351
- async_id trigger_async_id,
352
- async_context* result);
353
- // call node::EmitAsyncDestroy
354
- EMNAPI_INTERNAL_EXTERN void _emnapi_node_emit_async_destroy(async_id id, async_id trigger_async_id);
355
-
356
- // EMNAPI_INTERNAL_EXTERN void _emnapi_node_open_callback_scope(napi_value async_resource, async_id id, async_id trigger_async_id, int64_t* result);
357
- // EMNAPI_INTERNAL_EXTERN void _emnapi_node_close_callback_scope(int64_t* scope);
358
-
359
- // call node:MakeCallback
360
- EMNAPI_INTERNAL_EXTERN napi_status _emnapi_node_make_callback(napi_env env,
361
- napi_value async_resource,
362
- napi_value cb,
363
- napi_value* argv,
364
- size_t size,
365
- double async_id,
366
- double trigger_async_id,
367
- napi_value* result);
368
-
369
- #define ASYNC_RESOURCE_FIELD \
370
- napi_ref resource_; \
371
- async_context async_context_;
372
-
373
- typedef struct emnapi_async_resource {
374
- ASYNC_RESOURCE_FIELD
375
- } emnapi_async_resource;
376
-
377
- struct napi_async_work__ {
378
- ASYNC_RESOURCE_FIELD
379
- uv_work_t work_req_;
380
- napi_env env;
381
- void* data;
382
- napi_async_execute_callback execute;
383
- napi_async_complete_callback complete;
384
- };
385
-
386
- static void _emnapi_async_resource_ctor(napi_env env,
387
- napi_value resource,
388
- napi_value resource_name,
389
- emnapi_async_resource* ar) {
390
- EMNAPI_ASSERT_CALL(napi_create_reference(env, resource, 1, &ar->resource_));
391
- _emnapi_node_emit_async_init(resource, resource_name, -1.0, &ar->async_context_);
392
- }
393
-
394
- static void _emnapi_async_resource_dtor(napi_env env, emnapi_async_resource* ar) {
395
- EMNAPI_ASSERT_CALL(napi_delete_reference(env, ar->resource_));
396
- _emnapi_node_emit_async_destroy(ar->async_context_.async_id,
397
- ar->async_context_.trigger_async_id);
398
- }
399
-
400
- static napi_async_work async_work_init(
401
- napi_env env,
402
- napi_value async_resource,
403
- napi_value async_resource_name,
404
- napi_async_execute_callback execute,
405
- napi_async_complete_callback complete,
406
- void* data
407
- ) {
408
- napi_async_work work = (napi_async_work)calloc(1, sizeof(struct napi_async_work__));
409
- if (work == NULL) return NULL;
410
- _emnapi_async_resource_ctor(env, async_resource, async_resource_name, (emnapi_async_resource*)work);
411
- work->env = env;
412
- work->execute = execute;
413
- work->complete = complete;
414
- work->data = data;
415
- return work;
416
- }
417
-
418
- static void async_work_delete(napi_async_work work) {
419
- _emnapi_async_resource_dtor(work->env, (emnapi_async_resource*)work);
420
- free(work);
421
- }
422
-
423
- static void async_work_do_thread_pool_work(napi_async_work work) {
424
- work->execute(work->env, work->data);
425
- }
426
-
427
- typedef struct complete_wrap_s {
428
- int status;
429
- napi_async_work work;
430
- } complete_wrap_t;
431
-
432
- static napi_status convert_error_code(int code) {
433
- switch (code) {
434
- case 0:
435
- return napi_ok;
436
- case EINVAL:
437
- return napi_invalid_arg;
438
- case ECANCELED:
439
- return napi_cancelled;
440
- default:
441
- return napi_generic_failure;
442
- }
443
- }
444
-
445
- static void async_work_on_complete(napi_env env, void* args) {
446
- complete_wrap_t* wrap = (complete_wrap_t*) args;
447
- napi_status status = convert_error_code(wrap->status);
448
- napi_async_work work = wrap->work;
449
- free(wrap);
450
- napi_env _env = work->env;
451
- void* data = work->data;
452
- work->complete(_env, status, data);
453
- }
454
-
455
- static napi_value async_work_after_cb(napi_env env, napi_callback_info info) {
456
- void* data = NULL;
457
- EMNAPI_ASSERT_CALL(napi_get_cb_info(env, info, NULL, NULL, NULL, &data));
458
- complete_wrap_t* wrap = (complete_wrap_t*) data;
459
- _emnapi_call_into_module(env, async_work_on_complete, wrap, 1);
460
- return NULL;
461
- }
462
-
463
- static void async_work_after_thread_pool_work(napi_async_work work, int status) {
464
- if (work->complete == NULL) return;
465
- napi_handle_scope scope;
466
- napi_value resource, cb;
467
- napi_env env = work->env;
468
- EMNAPI_ASSERT_CALL(napi_open_handle_scope(env, &scope));
469
- EMNAPI_ASSERT_CALL(napi_get_reference_value(env, work->resource_, &resource));
470
- complete_wrap_t* wrap = (complete_wrap_t*) malloc(sizeof(complete_wrap_t));
471
- assert(wrap != NULL);
472
- wrap->status = status;
473
- wrap->work = work;
474
- if (emnapi_is_node_binding_available()) {
475
- EMNAPI_ASSERT_CALL(napi_create_function(env, NULL, 0, async_work_after_cb, wrap, &cb));
476
- _emnapi_node_make_callback(env,
477
- resource,
478
- cb,
479
- NULL,
480
- 0,
481
- work->async_context_.async_id,
482
- work->async_context_.trigger_async_id,
483
- NULL);
484
- } else {
485
- _emnapi_call_into_module(env, async_work_on_complete, wrap, 1);
486
- }
487
- EMNAPI_ASSERT_CALL(napi_close_handle_scope(env, scope));
488
- }
489
-
490
- static void async_work_schedule_work_on_execute(uv_work_t* req) {
491
- napi_async_work self = container_of(req, struct napi_async_work__, work_req_);
492
- async_work_do_thread_pool_work(self);
493
- }
494
-
495
- static void async_work_schedule_work_on_complete(uv_work_t* req, int status) {
496
- napi_async_work self = container_of(req, struct napi_async_work__, work_req_);
497
- EMNAPI_KEEPALIVE_POP();
498
- _emnapi_ctx_decrease_waiting_request_counter();
499
- async_work_after_thread_pool_work(self, status);
500
- }
501
-
502
- static void async_work_schedule_work(napi_async_work work) {
503
- EMNAPI_KEEPALIVE_PUSH();
504
- _emnapi_ctx_increase_waiting_request_counter();
505
- int status = uv_queue_work(uv_default_loop(),
506
- &work->work_req_,
507
- async_work_schedule_work_on_execute,
508
- async_work_schedule_work_on_complete);
509
- CHECK_EQ(status, 0);
510
- }
511
-
512
- static int async_work_cancel_work(napi_async_work work) {
513
- return uv_cancel((uv_req_t*)&work->work_req_);
514
- }
515
-
516
- #endif
517
-
518
- napi_status napi_create_async_work(napi_env env,
519
- napi_value async_resource,
520
- napi_value async_resource_name,
521
- napi_async_execute_callback execute,
522
- napi_async_complete_callback complete,
523
- void* data,
524
- napi_async_work* result) {
525
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
526
- CHECK_ENV(env);
527
- CHECK_ARG(env, execute);
528
- CHECK_ARG(env, result);
529
-
530
- napi_status status;
531
- napi_value resource;
532
- napi_value resource_name;
533
- if (async_resource != NULL) {
534
- status = napi_coerce_to_object(env, async_resource, &resource);
535
- if (status != napi_ok) return status;
536
- } else {
537
- status = napi_create_object(env, &resource);
538
- if (status != napi_ok) return status;
539
- }
540
-
541
- CHECK_ARG(env, async_resource_name);
542
- status = napi_coerce_to_string(env, async_resource_name, &resource_name);
543
- if (status != napi_ok) return status;
544
-
545
- napi_async_work work = async_work_init(env,
546
- resource,
547
- resource_name,
548
- execute,
549
- complete,
550
- data);
551
- if (work == NULL) {
552
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
553
- }
554
-
555
- *result = work;
556
-
557
- return napi_clear_last_error(env);
558
- #else
559
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
560
- #endif
561
- }
562
-
563
- napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
564
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
565
- CHECK_ENV(env);
566
- CHECK_ARG(env, work);
567
-
568
- async_work_delete(work);
569
-
570
- return napi_clear_last_error(env);
571
- #else
572
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
573
- #endif
574
- }
575
-
576
- napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
577
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
578
- CHECK_ENV(env);
579
- CHECK_ARG(env, work);
580
-
581
- async_work_schedule_work(work);
582
-
583
- return napi_clear_last_error(env);
584
- #else
585
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
586
- #endif
587
- }
588
-
589
- #define CALL_UV(env, condition) \
590
- do { \
591
- int result = (condition); \
592
- napi_status status = convert_error_code(result); \
593
- if (status != napi_ok) { \
594
- return napi_set_last_error(env, status, result, NULL); \
595
- } \
596
- } while (0)
597
-
598
- napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
599
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
600
- CHECK_ENV(env);
601
- CHECK_ARG(env, work);
602
-
603
- CALL_UV(env, async_work_cancel_work(work));
604
-
605
- return napi_clear_last_error(env);
606
- #else
607
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
608
- #endif
609
- }
610
-
611
- ////////////////////////////////////////////////////////////////////////////////
612
- // TSFN implementation
613
- ////////////////////////////////////////////////////////////////////////////////
614
-
615
- #if NAPI_VERSION >= 4 && (defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT))
616
-
617
- EMNAPI_INTERNAL_EXTERN void _emnapi_call_finalizer(napi_env env, napi_finalize cb, void* data, void* hint);
618
-
619
- static const unsigned char kDispatchIdle = 0;
620
- static const unsigned char kDispatchRunning = 1 << 0;
621
- static const unsigned char kDispatchPending = 1 << 1;
622
-
623
- static const unsigned int kMaxIterationCount = 1000;
624
-
625
- struct data_queue_node {
626
- void* data;
627
- void* q[2];
628
- };
629
-
630
- struct napi_threadsafe_function__ {
631
- ASYNC_RESOURCE_FIELD
632
- // These are variables protected by the mutex.
633
- pthread_mutex_t mutex;
634
- pthread_cond_t* cond;
635
- size_t queue_size;
636
- void* queue[2];
637
- uv_async_t async;
638
- size_t thread_count;
639
- bool is_closing;
640
- atomic_uchar dispatch_state;
641
-
642
- // These are variables set once, upon creation, and then never again, which
643
- // means we don't need the mutex to read them.
644
- void* context;
645
- size_t max_queue_size;
646
-
647
- // These are variables accessed only from the loop thread.
648
- napi_ref ref;
649
- napi_env env;
650
- void* finalize_data;
651
- napi_finalize finalize_cb;
652
- napi_threadsafe_function_call_js call_js_cb;
653
- bool handles_closing;
654
- bool async_ref;
655
- };
656
-
657
- static void _emnapi_tsfn_default_call_js(napi_env env, napi_value cb, void* context, void* data) {
658
- if (!(env == NULL || cb == NULL)) {
659
- napi_value recv;
660
- napi_status status;
661
-
662
- status = napi_get_undefined(env, &recv);
663
- if (status != napi_ok) {
664
- napi_throw_error(env, "ERR_NAPI_TSFN_GET_UNDEFINED",
665
- "Failed to retrieve undefined value");
666
- return;
667
- }
668
-
669
- status = napi_call_function(env, recv, cb, 0, NULL, NULL);
670
- if (status != napi_ok && status != napi_pending_exception) {
671
- napi_throw_error(env, "ERR_NAPI_TSFN_CALL_JS",
672
- "Failed to call JS callback");
673
- return;
674
- }
675
- }
676
- }
677
-
678
- static void _emnapi_tsfn_cleanup(void* data);
679
-
680
- static napi_threadsafe_function
681
- _emnapi_tsfn_create(napi_env env,
682
- napi_ref ref,
683
- napi_value async_resource,
684
- napi_value async_resource_name,
685
- size_t max_queue_size,
686
- size_t initial_thread_count,
687
- void* thread_finalize_data,
688
- napi_finalize thread_finalize_cb,
689
- void* context,
690
- napi_threadsafe_function_call_js call_js_cb) {
691
- napi_threadsafe_function ts_fn =
692
- (napi_threadsafe_function) calloc(1, sizeof(struct napi_threadsafe_function__));
693
- if (ts_fn == NULL) return NULL;
694
- _emnapi_async_resource_ctor(env, async_resource, async_resource_name, (emnapi_async_resource*) ts_fn);
695
- pthread_mutex_init(&ts_fn->mutex, NULL);
696
- ts_fn->cond = NULL;
697
- ts_fn->queue_size = 0;
698
- QUEUE_INIT(&ts_fn->queue);
699
- ts_fn->thread_count = initial_thread_count;
700
- ts_fn->is_closing = false;
701
- ts_fn->dispatch_state = kDispatchIdle;
702
-
703
- ts_fn->context = context;
704
- ts_fn->max_queue_size = max_queue_size;
705
-
706
- ts_fn->ref = ref;
707
- ts_fn->env = env;
708
- ts_fn->finalize_data = thread_finalize_data;
709
- ts_fn->finalize_cb = thread_finalize_cb;
710
- ts_fn->call_js_cb = call_js_cb;
711
- ts_fn->handles_closing = false;
712
-
713
- EMNAPI_ASSERT_CALL(napi_add_env_cleanup_hook(env, _emnapi_tsfn_cleanup, ts_fn));
714
- _emnapi_env_ref(env);
715
-
716
- EMNAPI_KEEPALIVE_PUSH();
717
- _emnapi_ctx_increase_waiting_request_counter();
718
- ts_fn->async_ref = true;
719
- return ts_fn;
720
- }
721
-
722
- static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
723
- if (func == NULL) return;
724
- pthread_mutex_destroy(&func->mutex);
725
- if (func->cond) {
726
- pthread_cond_destroy(func->cond);
727
- free(func->cond);
728
- func->cond = NULL;
729
- }
730
-
731
- QUEUE* tmp;
732
- struct data_queue_node* node;
733
- QUEUE_FOREACH(tmp, &func->queue) {
734
- node = QUEUE_DATA(tmp, struct data_queue_node, q);
735
- free(node);
736
- }
737
- QUEUE_INIT(&func->queue);
738
-
739
- if (func->ref != NULL) {
740
- EMNAPI_ASSERT_CALL(napi_delete_reference(func->env, func->ref));
741
- }
742
-
743
- EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(func->env, _emnapi_tsfn_cleanup, func));
744
- _emnapi_env_unref(func->env);
745
- if (func->async_ref) {
746
- EMNAPI_KEEPALIVE_POP();
747
- _emnapi_ctx_decrease_waiting_request_counter();
748
- func->async_ref = false;
749
- }
750
-
751
- _emnapi_async_resource_dtor(func->env, (emnapi_async_resource*) func);
752
- free(func);
753
- }
754
-
755
- static void _emnapi_tsfn_do_destroy(uv_handle_t* data) {
756
- napi_threadsafe_function func = container_of(data, struct napi_threadsafe_function__, async);
757
- _emnapi_tsfn_destroy(func);
758
- }
759
-
760
- static void _emnapi_tsfn_dispatch(napi_threadsafe_function func);
761
-
762
- // only main thread
763
- static void _emnapi_tsfn_async_cb(uv_async_t* data) {
764
- napi_threadsafe_function tsfn = container_of(data, struct napi_threadsafe_function__, async);
765
- _emnapi_tsfn_dispatch(tsfn);
766
- }
767
-
768
- // only main thread
769
- static napi_status _emnapi_tsfn_init(napi_threadsafe_function func) {
770
- uv_loop_t* loop = uv_default_loop();
771
- if (uv_async_init(loop, &func->async, _emnapi_tsfn_async_cb) == 0) {
772
- int r;
773
- if (func->max_queue_size > 0) {
774
- func->cond = (pthread_cond_t*) malloc(sizeof(pthread_cond_t));
775
- if (func->cond != NULL) {
776
- r = pthread_cond_init(func->cond, NULL);
777
- if (r != 0) {
778
- free(func->cond);
779
- func->cond = NULL;
780
- }
781
- }
782
- }
783
- if (func->max_queue_size == 0 || func->cond) {
784
- return napi_ok;
785
- }
786
- uv_close((uv_handle_t*) &func->async, _emnapi_tsfn_do_destroy);
787
- }
788
- _emnapi_tsfn_destroy(func);
789
- return napi_generic_failure;
790
- }
791
-
792
- static void _emnapi_tsfn_empty_queue_and_delete(napi_threadsafe_function func) {
793
- while (!QUEUE_EMPTY(&func->queue)) {
794
- QUEUE* q = QUEUE_HEAD(&func->queue);
795
- struct data_queue_node* node = QUEUE_DATA(q, struct data_queue_node, q);
796
-
797
- func->call_js_cb(NULL, NULL, func->context, node->data);
798
-
799
- QUEUE_REMOVE(q);
800
- QUEUE_INIT(q);
801
- func->queue_size--;
802
- free(node);
803
- }
804
- _emnapi_tsfn_destroy(func);
805
- }
806
-
807
- static napi_value _emnapi_tsfn_finalize_in_callback_scope(napi_env env, napi_callback_info info) {
808
- void* data = NULL;
809
- EMNAPI_ASSERT_CALL(napi_get_cb_info(env, info, NULL, NULL, NULL, &data));
810
- napi_threadsafe_function func = (napi_threadsafe_function) data;
811
- _emnapi_call_finalizer(func->env, func->finalize_cb, func->finalize_data, func->context);
812
- return NULL;
813
- }
814
-
815
- static void _emnapi_tsfn_finalize(napi_threadsafe_function func) {
816
- napi_handle_scope scope;
817
- EMNAPI_ASSERT_CALL(napi_open_handle_scope(func->env, &scope));
818
- if (func->finalize_cb) {
819
- if (emnapi_is_node_binding_available()) {
820
- napi_value resource, cb;
821
- EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->resource_, &resource));
822
- EMNAPI_ASSERT_CALL(napi_create_function(func->env, NULL, 0, _emnapi_tsfn_finalize_in_callback_scope, func, &cb));
823
- _emnapi_node_make_callback(func->env,
824
- resource,
825
- cb,
826
- NULL,
827
- 0,
828
- func->async_context_.async_id,
829
- func->async_context_.trigger_async_id,
830
- NULL);
831
- } else {
832
- _emnapi_call_finalizer(func->env, func->finalize_cb, func->finalize_data, func->context);
833
- }
834
- }
835
- _emnapi_tsfn_empty_queue_and_delete(func);
836
- EMNAPI_ASSERT_CALL(napi_close_handle_scope(func->env, scope));
837
- }
838
-
839
- static void _emnapi_tsfn_do_finalize(uv_handle_t* data) {
840
- napi_threadsafe_function func = container_of(data, struct napi_threadsafe_function__, async);
841
- _emnapi_tsfn_finalize(func);
842
- }
843
-
844
- static void _emnapi_tsfn_close_handles_and_maybe_delete(
845
- napi_threadsafe_function func, bool set_closing) {
846
- napi_handle_scope scope;
847
- EMNAPI_ASSERT_CALL(napi_open_handle_scope(func->env, &scope));
848
-
849
- if (set_closing) {
850
- pthread_mutex_lock(&func->mutex);
851
- func->is_closing = true;
852
- if (func->max_queue_size > 0) {
853
- pthread_cond_signal(func->cond);
854
- }
855
- pthread_mutex_unlock(&func->mutex);
856
- }
857
- if (func->handles_closing) {
858
- return;
859
- }
860
- func->handles_closing = true;
861
- uv_close((uv_handle_t*)&func->async, _emnapi_tsfn_do_finalize);
862
-
863
- EMNAPI_ASSERT_CALL(napi_close_handle_scope(func->env, scope));
864
- }
865
-
866
- static void _emnapi_tsfn_cleanup(void* data) {
867
- _emnapi_tsfn_close_handles_and_maybe_delete((napi_threadsafe_function) data, true);
868
- }
869
-
870
- static void _emnapi_tsfn_call_js_cb(napi_env env, void* arg) {
871
- void** args = (void**) arg;
872
- napi_threadsafe_function func = (napi_threadsafe_function) *args;
873
- napi_value js_callback = (napi_value) *(args + 1);
874
- void* data = *(args + 2);
875
- func->call_js_cb(func->env, js_callback, func->context, data);
876
- }
877
-
878
- static napi_value _emnapi_tsfn_call_js_cb_in_callback_scope(napi_env env, napi_callback_info info) {
879
- void* data = NULL;
880
- EMNAPI_ASSERT_CALL(napi_get_cb_info(env, info, NULL, NULL, NULL, &data));
881
- _emnapi_call_into_module(env, _emnapi_tsfn_call_js_cb, data, 1);
882
- return NULL;
883
- }
884
-
885
- // static void _emnapi_tsfn_
886
-
887
- // only main thread
888
- static bool _emnapi_tsfn_dispatch_one(napi_threadsafe_function func) {
889
- void* data = NULL;
890
- bool popped_value = false;
891
- bool has_more = false;
892
-
893
- {
894
- pthread_mutex_lock(&func->mutex);
895
-
896
- if (func->is_closing) {
897
- _emnapi_tsfn_close_handles_and_maybe_delete(func, false);
898
- } else {
899
- size_t size = func->queue_size;
900
- if (size > 0) {
901
- QUEUE* q = QUEUE_HEAD(&func->queue);
902
- struct data_queue_node* node = QUEUE_DATA(q, struct data_queue_node, q);
903
- QUEUE_REMOVE(q);
904
- QUEUE_INIT(q);
905
- func->queue_size--;
906
- data = node->data;
907
- free(node);
908
- popped_value = true;
909
- if (size == func->max_queue_size && func->max_queue_size > 0) {
910
- pthread_cond_signal(func->cond);
911
- }
912
- size--;
913
- }
914
-
915
- if (size == 0) {
916
- if (func->thread_count == 0) {
917
- func->is_closing = true;
918
- if (func->max_queue_size > 0) {
919
- pthread_cond_signal(func->cond);
920
- }
921
- _emnapi_tsfn_close_handles_and_maybe_delete(func, false);
922
- }
923
- } else {
924
- has_more = true;
925
- }
926
- }
927
- pthread_mutex_unlock(&func->mutex);
928
- }
929
-
930
- if (popped_value) {
931
- napi_handle_scope scope;
932
- EMNAPI_ASSERT_CALL(napi_open_handle_scope(func->env, &scope));
933
- napi_value js_callback = NULL;
934
- void* jscb_data[3] = { (void*)(func), NULL, data };
935
- if (func->ref != NULL) {
936
- EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->ref, &js_callback));
937
- jscb_data[1] = (void*)js_callback;
938
- }
939
-
940
- if (emnapi_is_node_binding_available()) {
941
- napi_value resource, cb;
942
- EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->resource_, &resource));
943
- EMNAPI_ASSERT_CALL(napi_create_function(func->env, NULL, 0, _emnapi_tsfn_call_js_cb_in_callback_scope, jscb_data, &cb));
944
- _emnapi_node_make_callback(func->env,
945
- resource,
946
- cb,
947
- NULL,
948
- 0,
949
- func->async_context_.async_id,
950
- func->async_context_.trigger_async_id,
951
- NULL);
952
- } else {
953
- _emnapi_call_into_module(func->env, _emnapi_tsfn_call_js_cb, jscb_data, 1);
954
- }
955
- EMNAPI_ASSERT_CALL(napi_close_handle_scope(func->env, scope));
956
- }
957
-
958
- return has_more;
959
- }
960
-
961
- // all threads
962
- static void _emnapi_tsfn_send(napi_threadsafe_function func) {
963
- unsigned char current_state =
964
- atomic_fetch_or(&func->dispatch_state, kDispatchPending);
965
- if ((current_state & kDispatchRunning) == kDispatchRunning) {
966
- return;
967
- }
968
- uv_async_send(&func->async);
969
- }
970
-
971
- // only main thread
972
- static void _emnapi_tsfn_dispatch(napi_threadsafe_function func) {
973
- bool has_more = true;
974
-
975
- // Limit maximum synchronous iteration count to prevent event loop
976
- // starvation. See `src/node_messaging.cc` for an inspiration.
977
- unsigned int iterations_left = kMaxIterationCount;
978
- while (has_more && --iterations_left != 0) {
979
- func->dispatch_state = kDispatchRunning;
980
- has_more = _emnapi_tsfn_dispatch_one(func);
981
-
982
- // Send() was called while we were executing the JS function
983
- if (atomic_exchange(&func->dispatch_state, kDispatchIdle) != kDispatchRunning) {
984
- has_more = true;
985
- }
986
- }
987
-
988
- if (has_more) {
989
- _emnapi_tsfn_send(func);
990
- }
991
- }
992
-
993
- #endif
994
-
995
- #if NAPI_VERSION >= 4
996
-
997
- napi_status
998
- napi_create_threadsafe_function(napi_env env,
999
- napi_value func,
1000
- napi_value async_resource,
1001
- napi_value async_resource_name,
1002
- size_t max_queue_size,
1003
- size_t initial_thread_count,
1004
- void* thread_finalize_data,
1005
- napi_finalize thread_finalize_cb,
1006
- void* context,
1007
- napi_threadsafe_function_call_js call_js_cb,
1008
- napi_threadsafe_function* result) {
1009
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1010
- CHECK_ENV(env);
1011
- // CHECK_ARG(env, async_resource_name);
1012
- RETURN_STATUS_IF_FALSE(env, initial_thread_count > 0, napi_invalid_arg);
1013
- CHECK_ARG(env, result);
1014
-
1015
- napi_status status = napi_ok;
1016
- napi_ref ref = NULL;
1017
-
1018
- if (func == NULL) {
1019
- CHECK_ARG(env, call_js_cb);
1020
- } else {
1021
- napi_valuetype type;
1022
- status = napi_typeof(env, func, &type);
1023
- if (status != napi_ok) return napi_set_last_error(env, status, 0, NULL);
1024
- if (type != napi_function) {
1025
- return napi_set_last_error(env, napi_invalid_arg, 0, NULL);
1026
- }
1027
- status = napi_create_reference(env, func, 1, &ref);
1028
- if (status != napi_ok) return napi_set_last_error(env, status, 0, NULL);
1029
- }
1030
-
1031
- napi_value resource;
1032
- napi_value resource_name;
1033
- if (async_resource != NULL) {
1034
- status = napi_coerce_to_object(env, async_resource, &resource);
1035
- if (status != napi_ok) return status;
1036
- } else {
1037
- status = napi_create_object(env, &resource);
1038
- if (status != napi_ok) return status;
1039
- }
1040
-
1041
- CHECK_ARG(env, async_resource_name);
1042
- status = napi_coerce_to_string(env, async_resource_name, &resource_name);
1043
- if (status != napi_ok) return status;
1044
-
1045
- napi_threadsafe_function ts_fn = _emnapi_tsfn_create(
1046
- env,
1047
- ref,
1048
- resource,
1049
- resource_name,
1050
- max_queue_size,
1051
- initial_thread_count,
1052
- thread_finalize_data,
1053
- thread_finalize_cb,
1054
- context,
1055
- call_js_cb != NULL ? call_js_cb : _emnapi_tsfn_default_call_js);
1056
-
1057
- if (ts_fn == NULL) {
1058
- status = napi_generic_failure;
1059
- } else {
1060
- // Init deletes ts_fn upon failure.
1061
- status = _emnapi_tsfn_init(ts_fn);
1062
- if (status == napi_ok) {
1063
- *result = ts_fn;
1064
- }
1065
- }
1066
-
1067
- return napi_set_last_error(env, status, 0, NULL);
1068
- #else
1069
- return napi_set_last_error(env, napi_generic_failure, 0, NULL);
1070
- #endif
1071
- }
1072
-
1073
- napi_status
1074
- napi_get_threadsafe_function_context(napi_threadsafe_function func,
1075
- void** result) {
1076
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1077
- CHECK_NOT_NULL(func);
1078
- CHECK_NOT_NULL(result);
1079
-
1080
- *result = func->context;
1081
-
1082
- return napi_ok;
1083
- #else
1084
- return napi_generic_failure;
1085
- #endif
1086
- }
1087
-
1088
- napi_status
1089
- napi_call_threadsafe_function(napi_threadsafe_function func,
1090
- void* data,
1091
- napi_threadsafe_function_call_mode mode) {
1092
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1093
- CHECK_NOT_NULL(func);
1094
- pthread_mutex_lock(&func->mutex);
1095
-
1096
- while (func->queue_size >= func->max_queue_size &&
1097
- func->max_queue_size > 0 &&
1098
- !func->is_closing) {
1099
- if (mode == napi_tsfn_nonblocking) {
1100
- pthread_mutex_unlock(&func->mutex);
1101
- return napi_queue_full;
1102
- }
1103
- pthread_cond_wait(func->cond, &func->mutex);
1104
- }
1105
-
1106
- if (func->is_closing) {
1107
- if (func->thread_count == 0) {
1108
- pthread_mutex_unlock(&func->mutex);
1109
- return napi_invalid_arg;
1110
- } else {
1111
- func->thread_count--;
1112
- pthread_mutex_unlock(&func->mutex);
1113
- return napi_closing;
1114
- }
1115
- } else {
1116
- struct data_queue_node* queue_node = (struct data_queue_node*) malloc(sizeof(struct data_queue_node));
1117
- if (queue_node == NULL) {
1118
- pthread_mutex_unlock(&func->mutex);
1119
- return napi_generic_failure;
1120
- }
1121
- queue_node->data = data;
1122
- QUEUE_INSERT_TAIL(&func->queue, &queue_node->q);
1123
- func->queue_size++;
1124
- _emnapi_tsfn_send(func);
1125
- pthread_mutex_unlock(&func->mutex);
1126
- return napi_ok;
1127
- }
1128
- #else
1129
- return napi_generic_failure;
1130
- #endif
1131
- }
1132
-
1133
- napi_status
1134
- napi_acquire_threadsafe_function(napi_threadsafe_function func) {
1135
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1136
- CHECK_NOT_NULL(func);
1137
- pthread_mutex_lock(&func->mutex);
1138
-
1139
- if (func->is_closing) {
1140
- pthread_mutex_unlock(&func->mutex);
1141
- return napi_closing;
1142
- }
1143
-
1144
- func->thread_count++;
1145
-
1146
- pthread_mutex_unlock(&func->mutex);
1147
- return napi_ok;
1148
- #else
1149
- return napi_generic_failure;
1150
- #endif
1151
- }
1152
-
1153
- napi_status
1154
- napi_release_threadsafe_function(napi_threadsafe_function func,
1155
- napi_threadsafe_function_release_mode mode) {
1156
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1157
- CHECK_NOT_NULL(func);
1158
- pthread_mutex_lock(&func->mutex);
1159
-
1160
- if (func->thread_count == 0) {
1161
- pthread_mutex_unlock(&func->mutex);
1162
- return napi_invalid_arg;
1163
- }
1164
-
1165
- func->thread_count--;
1166
-
1167
- if (func->thread_count == 0 || mode == napi_tsfn_abort) {
1168
- if (!func->is_closing) {
1169
- func->is_closing = (mode == napi_tsfn_abort);
1170
- if (func->is_closing && func->max_queue_size > 0) {
1171
- pthread_cond_signal(func->cond);
1172
- }
1173
-
1174
- _emnapi_tsfn_send(func);
1175
- }
1176
- }
1177
-
1178
- pthread_mutex_unlock(&func->mutex);
1179
-
1180
- return napi_ok;
1181
- #else
1182
- return napi_generic_failure;
1183
- #endif
1184
- }
1185
-
1186
- napi_status
1187
- napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1188
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1189
- if (func->async_ref) {
1190
- EMNAPI_KEEPALIVE_POP();
1191
- _emnapi_ctx_decrease_waiting_request_counter();
1192
- func->async_ref = false;
1193
- }
1194
- return napi_ok;
1195
- #else
1196
- return napi_generic_failure;
1197
- #endif
1198
- }
1199
-
1200
- napi_status
1201
- napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
1202
- #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
1203
- if (!func->async_ref) {
1204
- EMNAPI_KEEPALIVE_PUSH();
1205
- _emnapi_ctx_increase_waiting_request_counter();
1206
- func->async_ref = true;
1207
- }
1208
- return napi_ok;
1209
- #else
1210
- return napi_generic_failure;
1211
- #endif
1212
- }
1213
-
1214
- #endif
1215
-
1216
- ////////////////////////////////////////////////////////////////////////////////
1217
- // Async cleanup hook implementation
1218
- ////////////////////////////////////////////////////////////////////////////////
1219
-
1220
- #if NAPI_VERSION >= 8
1221
-
1222
- typedef void (*async_cleanup_hook)(void* arg, void(*)(void*), void*);
1223
-
1224
- struct async_cleanup_hook_info {
1225
- napi_env env;
1226
- async_cleanup_hook fun;
1227
- void* arg;
1228
- bool started;
1229
- };
1230
-
1231
- struct napi_async_cleanup_hook_handle__ {
1232
- struct async_cleanup_hook_info* handle_;
1233
- napi_env env_;
1234
- napi_async_cleanup_hook user_hook_;
1235
- void* user_data_;
1236
- void (*done_cb_)(void*);
1237
- void* done_data_;
1238
- };
1239
-
1240
- static void _emnapi_ach_handle_hook(void* data, void (*done_cb)(void*), void* done_data) {
1241
- napi_async_cleanup_hook_handle handle =
1242
- (napi_async_cleanup_hook_handle) (data);
1243
- handle->done_cb_ = done_cb;
1244
- handle->done_data_ = done_data;
1245
- handle->user_hook_(handle, handle->user_data_);
1246
- }
1247
-
1248
- static void _emnapi_finish_async_cleanup_hook(void* arg) {
1249
- // struct async_cleanup_hook_info* info = (struct async_cleanup_hook_info*) (arg);
1250
- EMNAPI_KEEPALIVE_POP();
1251
- _emnapi_ctx_decrease_waiting_request_counter();
1252
- }
1253
-
1254
- static void _emnapi_run_async_cleanup_hook(void* arg) {
1255
- struct async_cleanup_hook_info* info = (struct async_cleanup_hook_info*) (arg);
1256
- EMNAPI_KEEPALIVE_PUSH();
1257
- _emnapi_ctx_increase_waiting_request_counter();
1258
- info->started = true;
1259
- info->fun(info->arg, _emnapi_finish_async_cleanup_hook, info);
1260
- }
1261
-
1262
- static struct async_cleanup_hook_info*
1263
- _emnapi_add_async_environment_cleanup_hook(napi_env env,
1264
- async_cleanup_hook fun,
1265
- void* arg) {
1266
- struct async_cleanup_hook_info* info =
1267
- (struct async_cleanup_hook_info*) malloc(sizeof(struct async_cleanup_hook_info));
1268
- info->env = env;
1269
- info->fun = fun;
1270
- info->arg = arg;
1271
- info->started = false;
1272
-
1273
- EMNAPI_ASSERT_CALL(napi_add_env_cleanup_hook(env, _emnapi_run_async_cleanup_hook, info));
1274
-
1275
- return info;
1276
- }
1277
-
1278
- static void _emnapi_remove_async_environment_cleanup_hook(
1279
- struct async_cleanup_hook_info* info) {
1280
- if (info->started) return;
1281
- EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(info->env, _emnapi_run_async_cleanup_hook, info));
1282
- }
1283
-
1284
- static napi_async_cleanup_hook_handle
1285
- _emnapi_ach_handle_create(napi_env env,
1286
- napi_async_cleanup_hook user_hook,
1287
- void* user_data) {
1288
- napi_async_cleanup_hook_handle handle =
1289
- (napi_async_cleanup_hook_handle) calloc(1, sizeof(struct napi_async_cleanup_hook_handle__));
1290
- handle->env_ = env;
1291
- handle->user_hook_ = user_hook;
1292
- handle->user_data_ = user_data;
1293
- handle->handle_ = _emnapi_add_async_environment_cleanup_hook(env, _emnapi_ach_handle_hook, handle);
1294
- _emnapi_env_ref(env);
1295
-
1296
- return handle;
1297
- }
1298
-
1299
- EMNAPI_INTERNAL_EXTERN void _emnapi_set_immediate(void (*callback)(void*), void* data);
1300
-
1301
- static void _emnapi_ach_handle_env_unref(void* arg) {
1302
- napi_env env = (napi_env) arg;
1303
- _emnapi_env_unref(env);
1304
- }
1305
-
1306
- static void
1307
- _emnapi_ach_handle_delete(napi_async_cleanup_hook_handle handle) {
1308
- _emnapi_remove_async_environment_cleanup_hook(handle->handle_);
1309
- if (handle->done_cb_ != NULL) handle->done_cb_(handle->done_data_);
1310
-
1311
- _emnapi_set_immediate(_emnapi_ach_handle_env_unref, handle->env_);
1312
-
1313
- free(handle->handle_);
1314
- free(handle);
1315
- }
1316
-
1317
- napi_status
1318
- napi_add_async_cleanup_hook(napi_env env,
1319
- napi_async_cleanup_hook hook,
1320
- void* arg,
1321
- napi_async_cleanup_hook_handle* remove_handle) {
1322
- CHECK_ENV(env);
1323
- CHECK_ARG(env, hook);
1324
-
1325
- napi_async_cleanup_hook_handle handle =
1326
- _emnapi_ach_handle_create(env, hook, arg);
1327
-
1328
- if (remove_handle != NULL) *remove_handle = handle;
1329
-
1330
- return napi_clear_last_error(env);
1331
- }
1332
-
1333
- napi_status
1334
- napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle) {
1335
- if (remove_handle == NULL) return napi_invalid_arg;
1336
-
1337
- _emnapi_ach_handle_delete(remove_handle);
1338
-
1339
- return napi_ok;
1340
- }
1341
-
1342
- #endif
1343
-
1344
21
  EXTERN_C_END