emnapi 1.8.0 → 1.9.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 +12 -13
- package/dist/library_napi.js +252 -120
- package/emnapi.gyp +8 -1
- package/include/node/emnapi.h +2 -1
- package/include/node/js_native_api.h +6 -6
- package/include/node/js_native_api_types.h +8 -7
- package/index.d.ts +12 -0
- package/index.js +36 -0
- package/lib/wasm32/libdlmalloc-mt.a +0 -0
- package/lib/wasm32/libdlmalloc.a +0 -0
- package/lib/wasm32/libemmalloc-mt.a +0 -0
- package/lib/wasm32/libemmalloc.a +0 -0
- package/lib/wasm32/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32/libemnapi-basic.a +0 -0
- package/lib/wasm32/libemnapi.a +0 -0
- package/lib/wasm32-emscripten/libemnapi-basic.a +0 -0
- package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
- package/lib/wasm32-emscripten/libemnapi.a +0 -0
- package/lib/wasm32-wasi/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32-wasi/libemnapi-basic.a +0 -0
- package/lib/wasm32-wasi/libemnapi.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi-basic-napi-rs-mt.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi-basic.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi-mt.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi-napi-rs-mt.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi.a +0 -0
- package/lib/wasm32-wasip1/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32-wasip1/libemnapi-basic.a +0 -0
- package/lib/wasm32-wasip1/libemnapi.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi-basic-mt.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi-basic-napi-rs-mt.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi-basic.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi-mt.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi-napi-rs-mt.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi.a +0 -0
- package/lib/wasm64-emscripten/libemnapi-basic.a +0 -0
- package/lib/wasm64-emscripten/libemnapi-mt.a +0 -0
- package/lib/wasm64-emscripten/libemnapi.a +0 -0
- package/package.json +5 -2
- package/src/async_cleanup_hook.c +0 -2
- package/src/emnapi_internal.h +12 -0
- package/src/node_api.c +1 -7
- package/src/thread/async_worker_create.c +24 -1
- package/src/threadsafe_function.c +110 -94
- package/src/threadsafe_function.h +51 -0
- package/src/uv/uv-common.c +9 -1
- package/src/wasi_wait.c +3 -0
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
#include "emnapi_internal.h"
|
|
3
3
|
|
|
4
4
|
#if NAPI_VERSION >= 4 && EMNAPI_HAVE_THREADS
|
|
5
|
-
#include
|
|
6
|
-
#include <pthread.h>
|
|
7
|
-
#include <errno.h>
|
|
8
|
-
#include "uv.h"
|
|
9
|
-
#include "uv/queue.h"
|
|
5
|
+
#include "threadsafe_function.h"
|
|
10
6
|
|
|
11
7
|
EXTERN_C_START
|
|
12
8
|
|
|
@@ -23,33 +19,6 @@ struct data_queue_node {
|
|
|
23
19
|
struct uv__queue q;
|
|
24
20
|
};
|
|
25
21
|
|
|
26
|
-
struct napi_threadsafe_function__ {
|
|
27
|
-
ASYNC_RESOURCE_FIELD
|
|
28
|
-
// These are variables protected by the mutex.
|
|
29
|
-
pthread_mutex_t mutex;
|
|
30
|
-
pthread_cond_t* cond;
|
|
31
|
-
size_t queue_size;
|
|
32
|
-
struct uv__queue queue;
|
|
33
|
-
uv_async_t async;
|
|
34
|
-
size_t thread_count;
|
|
35
|
-
bool is_closing;
|
|
36
|
-
atomic_uchar dispatch_state;
|
|
37
|
-
|
|
38
|
-
// These are variables set once, upon creation, and then never again, which
|
|
39
|
-
// means we don't need the mutex to read them.
|
|
40
|
-
void* context;
|
|
41
|
-
size_t max_queue_size;
|
|
42
|
-
|
|
43
|
-
// These are variables accessed only from the loop thread.
|
|
44
|
-
napi_ref ref;
|
|
45
|
-
napi_env env;
|
|
46
|
-
void* finalize_data;
|
|
47
|
-
napi_finalize finalize_cb;
|
|
48
|
-
napi_threadsafe_function_call_js call_js_cb;
|
|
49
|
-
bool handles_closing;
|
|
50
|
-
bool async_ref;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
22
|
static void _emnapi_tsfn_default_call_js(napi_env env, napi_value cb, void* context, void* data) {
|
|
54
23
|
if (!(env == NULL || cb == NULL)) {
|
|
55
24
|
napi_value recv;
|
|
@@ -87,13 +56,14 @@ _emnapi_tsfn_create(napi_env env,
|
|
|
87
56
|
napi_threadsafe_function ts_fn =
|
|
88
57
|
(napi_threadsafe_function) calloc(1, sizeof(struct napi_threadsafe_function__));
|
|
89
58
|
if (ts_fn == NULL) return NULL;
|
|
90
|
-
EMNAPI_ASYNC_RESOURCE_CTOR(env, async_resource, async_resource_name, (emnapi_async_resource*) ts_fn);
|
|
59
|
+
EMNAPI_ASYNC_RESOURCE_CTOR(env, async_resource, async_resource_name, (emnapi_async_resource*) &ts_fn->async_resource);
|
|
60
|
+
ts_fn->async_resource.is_some = true;
|
|
91
61
|
pthread_mutex_init(&ts_fn->mutex, NULL);
|
|
92
62
|
ts_fn->cond = NULL;
|
|
93
63
|
ts_fn->queue_size = 0;
|
|
94
64
|
uv__queue_init(&ts_fn->queue);
|
|
95
65
|
ts_fn->thread_count = initial_thread_count;
|
|
96
|
-
ts_fn->
|
|
66
|
+
ts_fn->state = napi_tsfn_state_open;
|
|
97
67
|
ts_fn->dispatch_state = kDispatchIdle;
|
|
98
68
|
|
|
99
69
|
ts_fn->context = context;
|
|
@@ -109,12 +79,29 @@ _emnapi_tsfn_create(napi_env env,
|
|
|
109
79
|
EMNAPI_ASSERT_CALL(napi_add_env_cleanup_hook(env, _emnapi_tsfn_cleanup, ts_fn));
|
|
110
80
|
_emnapi_env_ref(env);
|
|
111
81
|
|
|
112
|
-
|
|
113
|
-
_emnapi_ctx_increase_waiting_request_counter();
|
|
114
|
-
ts_fn->async_ref = true;
|
|
82
|
+
ts_fn->async_ref = 0;
|
|
115
83
|
return ts_fn;
|
|
116
84
|
}
|
|
117
85
|
|
|
86
|
+
static void _emnapi_tsfn_release_resources(napi_threadsafe_function func) {
|
|
87
|
+
if (func->state != napi_tsfn_state_closed) {
|
|
88
|
+
func->state = napi_tsfn_state_closed;
|
|
89
|
+
if (func->ref != NULL) {
|
|
90
|
+
EMNAPI_ASSERT_CALL(napi_delete_reference(func->env, func->ref));
|
|
91
|
+
func->ref = NULL;
|
|
92
|
+
}
|
|
93
|
+
EMNAPI_ASYNC_RESOURCE_DTOR(func->env, (emnapi_async_resource*) &func->async_resource);
|
|
94
|
+
func->async_resource.is_some = false;
|
|
95
|
+
EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(func->env, _emnapi_tsfn_cleanup, func));
|
|
96
|
+
_emnapi_env_unref(func->env);
|
|
97
|
+
if (func->async_ref > 0) {
|
|
98
|
+
func->async_ref = 0;
|
|
99
|
+
EMNAPI_KEEPALIVE_POP();
|
|
100
|
+
_emnapi_ctx_decrease_waiting_request_counter();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
118
105
|
static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
|
|
119
106
|
if (func == NULL) return;
|
|
120
107
|
pthread_mutex_destroy(&func->mutex);
|
|
@@ -131,20 +118,7 @@ static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
|
|
|
131
118
|
free(node);
|
|
132
119
|
}
|
|
133
120
|
uv__queue_init(&func->queue);
|
|
134
|
-
|
|
135
|
-
if (func->ref != NULL) {
|
|
136
|
-
EMNAPI_ASSERT_CALL(napi_delete_reference(func->env, func->ref));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
EMNAPI_ASYNC_RESOURCE_DTOR(func->env, (emnapi_async_resource*) func);
|
|
140
|
-
|
|
141
|
-
EMNAPI_ASSERT_CALL(napi_remove_env_cleanup_hook(func->env, _emnapi_tsfn_cleanup, func));
|
|
142
|
-
_emnapi_env_unref(func->env);
|
|
143
|
-
if (func->async_ref) {
|
|
144
|
-
EMNAPI_KEEPALIVE_POP();
|
|
145
|
-
_emnapi_ctx_decrease_waiting_request_counter();
|
|
146
|
-
func->async_ref = false;
|
|
147
|
-
}
|
|
121
|
+
_emnapi_tsfn_release_resources(func);
|
|
148
122
|
|
|
149
123
|
free(func);
|
|
150
124
|
}
|
|
@@ -165,8 +139,12 @@ static void _emnapi_tsfn_async_cb(uv_async_t* data) {
|
|
|
165
139
|
// only main thread
|
|
166
140
|
static napi_status _emnapi_tsfn_init(napi_threadsafe_function func) {
|
|
167
141
|
uv_loop_t* loop = uv_default_loop();
|
|
142
|
+
bool should_delete = true;
|
|
168
143
|
if (uv_async_init(loop, &func->async, _emnapi_tsfn_async_cb) == 0) {
|
|
169
144
|
int r;
|
|
145
|
+
func->async_ref = 1;
|
|
146
|
+
EMNAPI_KEEPALIVE_PUSH();
|
|
147
|
+
_emnapi_ctx_increase_waiting_request_counter();
|
|
170
148
|
if (func->max_queue_size > 0) {
|
|
171
149
|
func->cond = (pthread_cond_t*) malloc(sizeof(pthread_cond_t));
|
|
172
150
|
if (func->cond != NULL) {
|
|
@@ -181,23 +159,44 @@ static napi_status _emnapi_tsfn_init(napi_threadsafe_function func) {
|
|
|
181
159
|
return napi_ok;
|
|
182
160
|
}
|
|
183
161
|
uv_close((uv_handle_t*) &func->async, _emnapi_tsfn_do_destroy);
|
|
162
|
+
should_delete = false;
|
|
163
|
+
}
|
|
164
|
+
if (should_delete) {
|
|
165
|
+
_emnapi_tsfn_destroy(func);
|
|
184
166
|
}
|
|
185
|
-
_emnapi_tsfn_destroy(func);
|
|
186
167
|
return napi_generic_failure;
|
|
187
168
|
}
|
|
188
169
|
|
|
189
|
-
static void
|
|
190
|
-
|
|
191
|
-
|
|
170
|
+
static void _emnapi_tsfn_empty_queue(napi_threadsafe_function func) {
|
|
171
|
+
struct uv__queue drain_queue;
|
|
172
|
+
uv__queue_init(&drain_queue);
|
|
173
|
+
pthread_mutex_lock(&func->mutex);
|
|
174
|
+
uv__queue_move(&func->queue, &drain_queue);
|
|
175
|
+
uv__queue_init(&func->queue);
|
|
176
|
+
func->queue_size = 0;
|
|
177
|
+
pthread_mutex_unlock(&func->mutex);
|
|
178
|
+
|
|
179
|
+
while (!uv__queue_empty(&drain_queue)) {
|
|
180
|
+
struct uv__queue* q = uv__queue_head(&drain_queue);
|
|
192
181
|
struct data_queue_node* node = uv__queue_data(q, struct data_queue_node, q);
|
|
193
182
|
|
|
194
183
|
func->call_js_cb(NULL, NULL, func->context, node->data);
|
|
195
184
|
|
|
196
185
|
uv__queue_remove(q);
|
|
197
186
|
uv__queue_init(q);
|
|
198
|
-
func->queue_size--;
|
|
199
187
|
free(node);
|
|
200
188
|
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static void _emnapi_tsfn_maybe_delete(napi_threadsafe_function func) {
|
|
192
|
+
pthread_mutex_lock(&func->mutex);
|
|
193
|
+
if (func->thread_count > 0) {
|
|
194
|
+
_emnapi_tsfn_release_resources(func);
|
|
195
|
+
pthread_mutex_unlock(&func->mutex);
|
|
196
|
+
return;
|
|
197
|
+
} else {
|
|
198
|
+
pthread_mutex_unlock(&func->mutex);
|
|
199
|
+
}
|
|
201
200
|
_emnapi_tsfn_destroy(func);
|
|
202
201
|
}
|
|
203
202
|
|
|
@@ -211,24 +210,25 @@ static napi_value _emnapi_tsfn_finalize_in_callback_scope(napi_env env, napi_cal
|
|
|
211
210
|
|
|
212
211
|
static void _emnapi_tsfn_finalize(napi_threadsafe_function func) {
|
|
213
212
|
napi_handle_scope scope = _emnapi_open_handle_scope();
|
|
213
|
+
_emnapi_tsfn_empty_queue(func);
|
|
214
214
|
if (func->finalize_cb) {
|
|
215
215
|
if (emnapi_is_node_binding_available()) {
|
|
216
216
|
napi_value resource, cb;
|
|
217
|
-
EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->resource_, &resource));
|
|
218
|
-
EMNAPI_ASSERT_CALL(
|
|
217
|
+
EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->async_resource.resource_, &resource));
|
|
218
|
+
EMNAPI_ASSERT_CALL(_emnapi_create_function(func->env, NULL, 0, _emnapi_tsfn_finalize_in_callback_scope, func, &cb));
|
|
219
219
|
_emnapi_node_make_callback(func->env,
|
|
220
220
|
resource,
|
|
221
221
|
cb,
|
|
222
222
|
NULL,
|
|
223
223
|
0,
|
|
224
|
-
func->async_context_.async_id,
|
|
225
|
-
func->async_context_.trigger_async_id,
|
|
224
|
+
func->async_resource.async_context_.async_id,
|
|
225
|
+
func->async_resource.async_context_.trigger_async_id,
|
|
226
226
|
NULL);
|
|
227
227
|
} else {
|
|
228
228
|
_emnapi_call_finalizer(0, func->env, func->finalize_cb, func->finalize_data, func->context);
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
|
|
231
|
+
_emnapi_tsfn_maybe_delete(func);
|
|
232
232
|
_emnapi_close_handle_scope(scope);
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -244,13 +244,14 @@ static void _emnapi_tsfn_close_handles_and_maybe_delete(
|
|
|
244
244
|
|
|
245
245
|
if (set_closing) {
|
|
246
246
|
pthread_mutex_lock(&func->mutex);
|
|
247
|
-
func->
|
|
247
|
+
func->state = napi_tsfn_state_closing;
|
|
248
248
|
if (func->max_queue_size > 0) {
|
|
249
249
|
pthread_cond_signal(func->cond);
|
|
250
250
|
}
|
|
251
251
|
pthread_mutex_unlock(&func->mutex);
|
|
252
252
|
}
|
|
253
253
|
if (func->handles_closing) {
|
|
254
|
+
EMNAPI_ASSERT_CALL(napi_close_handle_scope(func->env, scope));
|
|
254
255
|
return;
|
|
255
256
|
}
|
|
256
257
|
func->handles_closing = true;
|
|
@@ -289,9 +290,7 @@ static bool _emnapi_tsfn_dispatch_one(napi_threadsafe_function func) {
|
|
|
289
290
|
{
|
|
290
291
|
pthread_mutex_lock(&func->mutex);
|
|
291
292
|
|
|
292
|
-
if (func->
|
|
293
|
-
_emnapi_tsfn_close_handles_and_maybe_delete(func, false);
|
|
294
|
-
} else {
|
|
293
|
+
if (func->state == napi_tsfn_state_open) {
|
|
295
294
|
size_t size = func->queue_size;
|
|
296
295
|
if (size > 0) {
|
|
297
296
|
struct uv__queue* q = uv__queue_head(&func->queue);
|
|
@@ -310,7 +309,7 @@ static bool _emnapi_tsfn_dispatch_one(napi_threadsafe_function func) {
|
|
|
310
309
|
|
|
311
310
|
if (size == 0) {
|
|
312
311
|
if (func->thread_count == 0) {
|
|
313
|
-
func->
|
|
312
|
+
func->state = napi_tsfn_state_closing;
|
|
314
313
|
if (func->max_queue_size > 0) {
|
|
315
314
|
pthread_cond_signal(func->cond);
|
|
316
315
|
}
|
|
@@ -319,6 +318,8 @@ static bool _emnapi_tsfn_dispatch_one(napi_threadsafe_function func) {
|
|
|
319
318
|
} else {
|
|
320
319
|
has_more = true;
|
|
321
320
|
}
|
|
321
|
+
} else {
|
|
322
|
+
_emnapi_tsfn_close_handles_and_maybe_delete(func, false);
|
|
322
323
|
}
|
|
323
324
|
pthread_mutex_unlock(&func->mutex);
|
|
324
325
|
}
|
|
@@ -335,15 +336,15 @@ static bool _emnapi_tsfn_dispatch_one(napi_threadsafe_function func) {
|
|
|
335
336
|
|
|
336
337
|
if (emnapi_is_node_binding_available()) {
|
|
337
338
|
napi_value resource, cb;
|
|
338
|
-
EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->resource_, &resource));
|
|
339
|
-
EMNAPI_ASSERT_CALL(
|
|
339
|
+
EMNAPI_ASSERT_CALL(napi_get_reference_value(func->env, func->async_resource.resource_, &resource));
|
|
340
|
+
EMNAPI_ASSERT_CALL(_emnapi_create_function(func->env, NULL, 0, _emnapi_tsfn_call_js_cb_in_callback_scope, jscb_data, &cb));
|
|
340
341
|
_emnapi_node_make_callback(func->env,
|
|
341
342
|
resource,
|
|
342
343
|
cb,
|
|
343
344
|
NULL,
|
|
344
345
|
0,
|
|
345
|
-
func->async_context_.async_id,
|
|
346
|
-
func->async_context_.trigger_async_id,
|
|
346
|
+
func->async_resource.async_context_.async_id,
|
|
347
|
+
func->async_resource.async_context_.trigger_async_id,
|
|
347
348
|
NULL);
|
|
348
349
|
} else {
|
|
349
350
|
_emnapi_callback_into_module(0, func->env, _emnapi_tsfn_call_js_cb, jscb_data, 1);
|
|
@@ -494,7 +495,7 @@ napi_call_threadsafe_function(napi_threadsafe_function func,
|
|
|
494
495
|
|
|
495
496
|
while (func->queue_size >= func->max_queue_size &&
|
|
496
497
|
func->max_queue_size > 0 &&
|
|
497
|
-
|
|
498
|
+
func->state == napi_tsfn_state_open) {
|
|
498
499
|
if (mode == napi_tsfn_nonblocking) {
|
|
499
500
|
pthread_mutex_unlock(&func->mutex);
|
|
500
501
|
return napi_queue_full;
|
|
@@ -502,16 +503,7 @@ napi_call_threadsafe_function(napi_threadsafe_function func,
|
|
|
502
503
|
pthread_cond_wait(func->cond, &func->mutex);
|
|
503
504
|
}
|
|
504
505
|
|
|
505
|
-
if (func->
|
|
506
|
-
if (func->thread_count == 0) {
|
|
507
|
-
pthread_mutex_unlock(&func->mutex);
|
|
508
|
-
return napi_invalid_arg;
|
|
509
|
-
} else {
|
|
510
|
-
func->thread_count--;
|
|
511
|
-
pthread_mutex_unlock(&func->mutex);
|
|
512
|
-
return napi_closing;
|
|
513
|
-
}
|
|
514
|
-
} else {
|
|
506
|
+
if (func->state == napi_tsfn_state_open) {
|
|
515
507
|
struct data_queue_node* queue_node = (struct data_queue_node*) malloc(sizeof(struct data_queue_node));
|
|
516
508
|
if (queue_node == NULL) {
|
|
517
509
|
pthread_mutex_unlock(&func->mutex);
|
|
@@ -524,6 +516,20 @@ napi_call_threadsafe_function(napi_threadsafe_function func,
|
|
|
524
516
|
pthread_mutex_unlock(&func->mutex);
|
|
525
517
|
return napi_ok;
|
|
526
518
|
}
|
|
519
|
+
|
|
520
|
+
if (func->thread_count == 0) {
|
|
521
|
+
pthread_mutex_unlock(&func->mutex);
|
|
522
|
+
return napi_invalid_arg;
|
|
523
|
+
}
|
|
524
|
+
func->thread_count--;
|
|
525
|
+
|
|
526
|
+
if (!(func->state == napi_tsfn_state_closed && func->thread_count == 0)) {
|
|
527
|
+
pthread_mutex_unlock(&func->mutex);
|
|
528
|
+
return napi_closing;
|
|
529
|
+
}
|
|
530
|
+
pthread_mutex_unlock(&func->mutex);
|
|
531
|
+
_emnapi_tsfn_destroy(func);
|
|
532
|
+
return napi_closing;
|
|
527
533
|
#else
|
|
528
534
|
return napi_generic_failure;
|
|
529
535
|
#endif
|
|
@@ -535,15 +541,14 @@ napi_acquire_threadsafe_function(napi_threadsafe_function func) {
|
|
|
535
541
|
CHECK_NOT_NULL(func);
|
|
536
542
|
pthread_mutex_lock(&func->mutex);
|
|
537
543
|
|
|
538
|
-
if (func->
|
|
544
|
+
if (func->state == napi_tsfn_state_open) {
|
|
545
|
+
func->thread_count++;
|
|
539
546
|
pthread_mutex_unlock(&func->mutex);
|
|
540
|
-
return
|
|
547
|
+
return napi_ok;
|
|
541
548
|
}
|
|
542
549
|
|
|
543
|
-
func->thread_count++;
|
|
544
|
-
|
|
545
550
|
pthread_mutex_unlock(&func->mutex);
|
|
546
|
-
return
|
|
551
|
+
return napi_closing;
|
|
547
552
|
#else
|
|
548
553
|
return napi_generic_failure;
|
|
549
554
|
#endif
|
|
@@ -564,9 +569,11 @@ napi_release_threadsafe_function(napi_threadsafe_function func,
|
|
|
564
569
|
func->thread_count--;
|
|
565
570
|
|
|
566
571
|
if (func->thread_count == 0 || mode == napi_tsfn_abort) {
|
|
567
|
-
if (
|
|
568
|
-
|
|
569
|
-
|
|
572
|
+
if (func->state == napi_tsfn_state_open) {
|
|
573
|
+
if (mode == napi_tsfn_abort) {
|
|
574
|
+
func->state = napi_tsfn_state_closing;
|
|
575
|
+
}
|
|
576
|
+
if (func->state == napi_tsfn_state_closing && func->max_queue_size > 0) {
|
|
570
577
|
pthread_cond_signal(func->cond);
|
|
571
578
|
}
|
|
572
579
|
|
|
@@ -574,7 +581,12 @@ napi_release_threadsafe_function(napi_threadsafe_function func,
|
|
|
574
581
|
}
|
|
575
582
|
}
|
|
576
583
|
|
|
584
|
+
if (!(func->state == napi_tsfn_state_closed && func->thread_count == 0)) {
|
|
585
|
+
pthread_mutex_unlock(&func->mutex);
|
|
586
|
+
return napi_ok;
|
|
587
|
+
}
|
|
577
588
|
pthread_mutex_unlock(&func->mutex);
|
|
589
|
+
_emnapi_tsfn_destroy(func);
|
|
578
590
|
|
|
579
591
|
return napi_ok;
|
|
580
592
|
#else
|
|
@@ -585,10 +597,13 @@ napi_release_threadsafe_function(napi_threadsafe_function func,
|
|
|
585
597
|
napi_status
|
|
586
598
|
napi_unref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function func) {
|
|
587
599
|
#if EMNAPI_HAVE_THREADS
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
func->async_ref
|
|
600
|
+
CHECK_NOT_NULL(func);
|
|
601
|
+
if (func->async_ref > 0) {
|
|
602
|
+
func->async_ref--;
|
|
603
|
+
if (func->async_ref == 0) {
|
|
604
|
+
EMNAPI_KEEPALIVE_POP();
|
|
605
|
+
_emnapi_ctx_decrease_waiting_request_counter();
|
|
606
|
+
}
|
|
592
607
|
}
|
|
593
608
|
return napi_ok;
|
|
594
609
|
#else
|
|
@@ -599,11 +614,12 @@ napi_unref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function
|
|
|
599
614
|
napi_status
|
|
600
615
|
napi_ref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function func) {
|
|
601
616
|
#if EMNAPI_HAVE_THREADS
|
|
617
|
+
CHECK_NOT_NULL(func);
|
|
602
618
|
if (!func->async_ref) {
|
|
603
619
|
EMNAPI_KEEPALIVE_PUSH();
|
|
604
620
|
_emnapi_ctx_increase_waiting_request_counter();
|
|
605
|
-
func->async_ref = true;
|
|
606
621
|
}
|
|
622
|
+
func->async_ref++;
|
|
607
623
|
return napi_ok;
|
|
608
624
|
#else
|
|
609
625
|
return napi_generic_failure;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#ifndef SRC_THREADSAFE_FUNCTION_H_
|
|
2
|
+
#define SRC_THREADSAFE_FUNCTION_H_
|
|
3
|
+
|
|
4
|
+
#include "node_api.h"
|
|
5
|
+
#include "emnapi_internal.h"
|
|
6
|
+
|
|
7
|
+
#include <stdatomic.h>
|
|
8
|
+
#include <pthread.h>
|
|
9
|
+
#include <errno.h>
|
|
10
|
+
#include "uv.h"
|
|
11
|
+
#include "uv/queue.h"
|
|
12
|
+
|
|
13
|
+
typedef struct optional_async_resource {
|
|
14
|
+
ASYNC_RESOURCE_FIELD
|
|
15
|
+
bool is_some;
|
|
16
|
+
} optional_async_resource;
|
|
17
|
+
|
|
18
|
+
typedef enum napi_threadsafe_function_state {
|
|
19
|
+
napi_tsfn_state_open,
|
|
20
|
+
napi_tsfn_state_closing,
|
|
21
|
+
napi_tsfn_state_closed
|
|
22
|
+
} napi_threadsafe_function_state;
|
|
23
|
+
|
|
24
|
+
struct napi_threadsafe_function__ {
|
|
25
|
+
optional_async_resource async_resource;
|
|
26
|
+
// These are variables protected by the mutex.
|
|
27
|
+
pthread_mutex_t mutex;
|
|
28
|
+
pthread_cond_t* cond;
|
|
29
|
+
size_t queue_size;
|
|
30
|
+
struct uv__queue queue;
|
|
31
|
+
uv_async_t async;
|
|
32
|
+
size_t thread_count;
|
|
33
|
+
napi_threadsafe_function_state state;
|
|
34
|
+
atomic_uchar dispatch_state;
|
|
35
|
+
|
|
36
|
+
// These are variables set once, upon creation, and then never again, which
|
|
37
|
+
// means we don't need the mutex to read them.
|
|
38
|
+
void* context;
|
|
39
|
+
size_t max_queue_size;
|
|
40
|
+
|
|
41
|
+
// These are variables accessed only from the loop thread.
|
|
42
|
+
napi_ref ref;
|
|
43
|
+
napi_env env;
|
|
44
|
+
void* finalize_data;
|
|
45
|
+
napi_finalize finalize_cb;
|
|
46
|
+
napi_threadsafe_function_call_js call_js_cb;
|
|
47
|
+
bool handles_closing;
|
|
48
|
+
unsigned int async_ref;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
#endif
|
package/src/uv/uv-common.c
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
#include <stddef.h>
|
|
2
|
+
|
|
1
3
|
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
|
|
2
4
|
|
|
3
5
|
#include <errno.h>
|
|
4
|
-
#include <stddef.h>
|
|
5
6
|
#include <stdlib.h>
|
|
6
7
|
#include <string.h>
|
|
7
8
|
#include "uv-common.h"
|
|
@@ -183,4 +184,11 @@ uint64_t uv_metrics_idle_time(uv_loop_t* loop) {
|
|
|
183
184
|
return idle_time;
|
|
184
185
|
}
|
|
185
186
|
|
|
187
|
+
#else
|
|
188
|
+
|
|
189
|
+
typedef struct uv_loop_s uv_loop_t;
|
|
190
|
+
uv_loop_t* uv_default_loop(void) {
|
|
191
|
+
return NULL;
|
|
192
|
+
}
|
|
193
|
+
|
|
186
194
|
#endif
|
package/src/wasi_wait.c
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
#include <stdio.h>
|
|
7
7
|
#include "emnapi_internal.h"
|
|
8
8
|
|
|
9
|
+
EMNAPI_INTERNAL_EXTERN void _emnapi_worker_ref(pthread_t pid);
|
|
10
|
+
|
|
9
11
|
struct __pthread {
|
|
10
12
|
unsigned char _[32];
|
|
11
13
|
volatile int cancel;
|
|
@@ -28,6 +30,7 @@ void emnapi_thread_crashed() {
|
|
|
28
30
|
|
|
29
31
|
void _emnapi_yield() {
|
|
30
32
|
if (crashed_thread_id) {
|
|
33
|
+
_emnapi_worker_ref(crashed_thread_id);
|
|
31
34
|
_emnapi_runtime_keepalive_push();
|
|
32
35
|
_emnapi_unwind();
|
|
33
36
|
}
|