emnapi 1.2.0 → 1.3.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 +13 -3
- package/dist/library_napi.js +54 -33
- package/emnapi.gyp +3 -0
- package/include/node/emnapi.h +1 -1
- package/include/node/js_native_api.h +30 -25
- package/include/node/js_native_api_types.h +13 -9
- package/include/node/node_api.h +13 -13
- package/include/node/uv/threadpool.h +1 -1
- package/include/node/uv/unix.h +4 -0
- package/include/node/uv.h +49 -6
- package/lib/wasm32/libemnapi.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.a +0 -0
- package/lib/wasm32-wasi-threads/libemnapi-basic-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.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.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi-mt.a +0 -0
- package/lib/wasm32-wasip1-threads/libemnapi.a +0 -0
- package/lib/wasm64-emscripten/libemnapi-mt.a +0 -0
- package/lib/wasm64-emscripten/libemnapi.a +0 -0
- package/package.json +1 -1
- package/src/async_cleanup_hook.c +1 -1
- package/src/async_work.c +2 -2
- package/src/emnapi_internal.h +2 -2
- package/src/js_native_api.c +2 -1
- package/src/node_api.c +5 -5
- package/src/threadsafe_function.c +20 -21
- package/src/uv/queue.h +68 -86
- package/src/uv/threadpool.c +58 -40
- package/src/uv/unix/async.c +67 -64
- package/src/uv/unix/core.c +36 -1
- package/src/uv/unix/internal.h +54 -0
- package/src/uv/unix/loop.c +40 -4
- package/src/uv/unix/posix-hrtime.c +40 -0
- package/src/uv/uv-common.c +123 -7
- package/src/uv/uv-common.h +137 -9
package/src/uv/threadpool.c
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* IN THE SOFTWARE.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
// from libuv 1.
|
|
22
|
+
// from libuv 1.48.0
|
|
23
23
|
|
|
24
24
|
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
|
|
25
25
|
|
|
@@ -43,10 +43,10 @@ static unsigned int slow_io_work_running;
|
|
|
43
43
|
static unsigned int nthreads;
|
|
44
44
|
static uv_thread_t* threads;
|
|
45
45
|
static uv_thread_t default_threads[4];
|
|
46
|
-
static
|
|
47
|
-
static
|
|
48
|
-
static
|
|
49
|
-
static
|
|
46
|
+
static struct uv__queue exit_message;
|
|
47
|
+
static struct uv__queue wq;
|
|
48
|
+
static struct uv__queue run_slow_work_message;
|
|
49
|
+
static struct uv__queue slow_io_pending_wq;
|
|
50
50
|
|
|
51
51
|
static unsigned int slow_work_thread_threshold(void) {
|
|
52
52
|
return (nthreads + 1) / 2;
|
|
@@ -60,8 +60,8 @@ EMNAPI_INTERNAL_EXTERN void _emnapi_worker_unref(uv_thread_t pid);
|
|
|
60
60
|
|
|
61
61
|
#ifdef __EMNAPI_WASI_THREADS__
|
|
62
62
|
EMNAPI_INTERNAL_EXTERN
|
|
63
|
-
void _emnapi_after_uvthreadpool_ready(void (*callback)(
|
|
64
|
-
|
|
63
|
+
void _emnapi_after_uvthreadpool_ready(void (*callback)(struct uv__queue* w, enum uv__work_kind kind),
|
|
64
|
+
struct uv__queue* w,
|
|
65
65
|
enum uv__work_kind kind);
|
|
66
66
|
EMNAPI_INTERNAL_EXTERN void _emnapi_tell_js_uvthreadpool(uv_thread_t* threads, unsigned int n);
|
|
67
67
|
EMNAPI_INTERNAL_EXTERN void _emnapi_emit_async_thread_ready();
|
|
@@ -72,7 +72,7 @@ EMNAPI_INTERNAL_EXTERN void _emnapi_emit_async_thread_ready();
|
|
|
72
72
|
*/
|
|
73
73
|
static void* worker(void* arg) {
|
|
74
74
|
struct uv__work* w;
|
|
75
|
-
|
|
75
|
+
struct uv__queue* q;
|
|
76
76
|
int is_slow_work;
|
|
77
77
|
#ifndef __EMNAPI_WASI_THREADS__
|
|
78
78
|
uv_sem_post((uv_sem_t*) arg);
|
|
@@ -87,49 +87,49 @@ static void* worker(void* arg) {
|
|
|
87
87
|
|
|
88
88
|
/* Keep waiting while either no work is present or only slow I/O
|
|
89
89
|
and we're at the threshold for that. */
|
|
90
|
-
while (
|
|
91
|
-
(
|
|
92
|
-
|
|
90
|
+
while (uv__queue_empty(&wq) ||
|
|
91
|
+
(uv__queue_head(&wq) == &run_slow_work_message &&
|
|
92
|
+
uv__queue_next(&run_slow_work_message) == &wq &&
|
|
93
93
|
slow_io_work_running >= slow_work_thread_threshold())) {
|
|
94
94
|
idle_threads += 1;
|
|
95
95
|
uv_cond_wait(&cond, &mutex);
|
|
96
96
|
idle_threads -= 1;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
q =
|
|
99
|
+
q = uv__queue_head(&wq);
|
|
100
100
|
if (q == &exit_message) {
|
|
101
101
|
uv_cond_signal(&cond);
|
|
102
102
|
uv_mutex_unlock(&mutex);
|
|
103
103
|
break;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
uv__queue_remove(q);
|
|
107
|
+
uv__queue_init(q); /* Signal uv_cancel() that the work req is executing. */
|
|
108
108
|
|
|
109
109
|
is_slow_work = 0;
|
|
110
110
|
if (q == &run_slow_work_message) {
|
|
111
111
|
/* If we're at the slow I/O threshold, re-schedule until after all
|
|
112
112
|
other work in the queue is done. */
|
|
113
113
|
if (slow_io_work_running >= slow_work_thread_threshold()) {
|
|
114
|
-
|
|
114
|
+
uv__queue_insert_tail(&wq, q);
|
|
115
115
|
continue;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/* If we encountered a request to run slow I/O work but there is none
|
|
119
119
|
to run, that means it's cancelled => Start over. */
|
|
120
|
-
if (
|
|
120
|
+
if (uv__queue_empty(&slow_io_pending_wq))
|
|
121
121
|
continue;
|
|
122
122
|
|
|
123
123
|
is_slow_work = 1;
|
|
124
124
|
slow_io_work_running++;
|
|
125
125
|
|
|
126
|
-
q =
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
q = uv__queue_head(&slow_io_pending_wq);
|
|
127
|
+
uv__queue_remove(q);
|
|
128
|
+
uv__queue_init(q);
|
|
129
129
|
|
|
130
130
|
/* If there is more slow I/O work, schedule it to be run as well. */
|
|
131
|
-
if (!
|
|
132
|
-
|
|
131
|
+
if (!uv__queue_empty(&slow_io_pending_wq)) {
|
|
132
|
+
uv__queue_insert_tail(&wq, &run_slow_work_message);
|
|
133
133
|
if (idle_threads > 0)
|
|
134
134
|
uv_cond_signal(&cond);
|
|
135
135
|
}
|
|
@@ -137,13 +137,13 @@ static void* worker(void* arg) {
|
|
|
137
137
|
|
|
138
138
|
uv_mutex_unlock(&mutex);
|
|
139
139
|
|
|
140
|
-
w =
|
|
140
|
+
w = uv__queue_data(q, struct uv__work, wq);
|
|
141
141
|
w->work(w);
|
|
142
142
|
|
|
143
143
|
uv_mutex_lock(&w->loop->wq_mutex);
|
|
144
144
|
w->work = NULL; /* Signal uv_cancel() that the work req is done
|
|
145
145
|
executing. */
|
|
146
|
-
|
|
146
|
+
uv__queue_insert_tail(&w->loop->wq, &w->wq);
|
|
147
147
|
uv_async_send(&w->loop->wq_async);
|
|
148
148
|
uv_mutex_unlock(&w->loop->wq_mutex);
|
|
149
149
|
|
|
@@ -159,12 +159,12 @@ static void* worker(void* arg) {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
|
|
162
|
-
static void post(
|
|
162
|
+
static void post(struct uv__queue* q, enum uv__work_kind kind) {
|
|
163
163
|
uv_mutex_lock(&mutex);
|
|
164
164
|
// if (kind == UV__WORK_SLOW_IO) {
|
|
165
165
|
// /* Insert into a separate queue. */
|
|
166
|
-
//
|
|
167
|
-
// if (!
|
|
166
|
+
// uv__queue_insert_tail(&slow_io_pending_wq, q);
|
|
167
|
+
// if (!uv__queue_empty(&run_slow_work_message)) {
|
|
168
168
|
// /* Running slow I/O tasks is already scheduled => Nothing to do here.
|
|
169
169
|
// The worker that runs said other task will schedule this one as well. */
|
|
170
170
|
// uv_mutex_unlock(&mutex);
|
|
@@ -173,7 +173,7 @@ static void post(QUEUE* q, enum uv__work_kind kind) {
|
|
|
173
173
|
// q = &run_slow_work_message;
|
|
174
174
|
// }
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
uv__queue_insert_tail(&wq, q);
|
|
177
177
|
if (idle_threads > 0)
|
|
178
178
|
uv_cond_signal(&cond);
|
|
179
179
|
uv_mutex_unlock(&mutex);
|
|
@@ -254,9 +254,9 @@ static void init_threads(void) {
|
|
|
254
254
|
if (uv_mutex_init(&mutex))
|
|
255
255
|
abort();
|
|
256
256
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
uv__queue_init(&wq);
|
|
258
|
+
uv__queue_init(&slow_io_pending_wq);
|
|
259
|
+
uv__queue_init(&run_slow_work_message);
|
|
260
260
|
|
|
261
261
|
#ifndef __EMNAPI_WASI_THREADS__
|
|
262
262
|
if (uv_sem_init(&sem, 0))
|
|
@@ -331,12 +331,13 @@ void uv__work_submit(uv_loop_t* loop,
|
|
|
331
331
|
static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
|
332
332
|
int cancelled;
|
|
333
333
|
|
|
334
|
+
uv_once(&once, init_once); /* Ensure |mutex| is initialized. */
|
|
334
335
|
uv_mutex_lock(&mutex);
|
|
335
336
|
uv_mutex_lock(&w->loop->wq_mutex);
|
|
336
337
|
|
|
337
|
-
cancelled = !
|
|
338
|
+
cancelled = !uv__queue_empty(&w->wq) && w->work != NULL;
|
|
338
339
|
if (cancelled)
|
|
339
|
-
|
|
340
|
+
uv__queue_remove(&w->wq);
|
|
340
341
|
|
|
341
342
|
uv_mutex_unlock(&w->loop->wq_mutex);
|
|
342
343
|
uv_mutex_unlock(&mutex);
|
|
@@ -346,7 +347,7 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
|
|
346
347
|
|
|
347
348
|
w->work = uv__cancelled;
|
|
348
349
|
uv_mutex_lock(&loop->wq_mutex);
|
|
349
|
-
|
|
350
|
+
uv__queue_insert_tail(&loop->wq, &w->wq);
|
|
350
351
|
uv_async_send(&loop->wq_async);
|
|
351
352
|
uv_mutex_unlock(&loop->wq_mutex);
|
|
352
353
|
|
|
@@ -357,22 +358,39 @@ static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
|
|
|
357
358
|
void uv__work_done(uv_async_t* handle) {
|
|
358
359
|
struct uv__work* w;
|
|
359
360
|
uv_loop_t* loop;
|
|
360
|
-
|
|
361
|
-
|
|
361
|
+
struct uv__queue* q;
|
|
362
|
+
struct uv__queue wq;
|
|
362
363
|
int err;
|
|
364
|
+
int nevents;
|
|
363
365
|
|
|
364
366
|
loop = container_of(handle, uv_loop_t, wq_async);
|
|
365
367
|
uv_mutex_lock(&loop->wq_mutex);
|
|
366
|
-
|
|
368
|
+
uv__queue_move(&loop->wq, &wq);
|
|
367
369
|
uv_mutex_unlock(&loop->wq_mutex);
|
|
368
370
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
371
|
+
nevents = 0;
|
|
372
|
+
|
|
373
|
+
while (!uv__queue_empty(&wq)) {
|
|
374
|
+
q = uv__queue_head(&wq);
|
|
375
|
+
uv__queue_remove(q);
|
|
372
376
|
|
|
373
377
|
w = container_of(q, struct uv__work, wq);
|
|
374
378
|
err = (w->work == uv__cancelled) ? ECANCELED : 0;
|
|
375
379
|
w->done(w, err);
|
|
380
|
+
nevents++;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/* This check accomplishes 2 things:
|
|
384
|
+
* 1. Even if the queue was empty, the call to uv__work_done() should count
|
|
385
|
+
* as an event. Which will have been added by the event loop when
|
|
386
|
+
* calling this callback.
|
|
387
|
+
* 2. Prevents accidental wrap around in case nevents == 0 events == 0.
|
|
388
|
+
*/
|
|
389
|
+
if (nevents > 1) {
|
|
390
|
+
/* Subtract 1 to counter the call to uv__work_done(). */
|
|
391
|
+
uv__metrics_inc_events(loop, nevents - 1);
|
|
392
|
+
if (uv__get_internal_fields(loop)->current_timeout == 0)
|
|
393
|
+
uv__metrics_inc_events_waiting(loop, nevents - 1);
|
|
376
394
|
}
|
|
377
395
|
}
|
|
378
396
|
|
|
@@ -388,7 +406,7 @@ static void uv__queue_done(struct uv__work* w, int err) {
|
|
|
388
406
|
uv_work_t* req;
|
|
389
407
|
|
|
390
408
|
req = container_of(w, uv_work_t, work_req);
|
|
391
|
-
uv__req_unregister(req->loop
|
|
409
|
+
uv__req_unregister(req->loop);
|
|
392
410
|
|
|
393
411
|
if (req->after_work_cb == NULL)
|
|
394
412
|
return;
|
package/src/uv/unix/async.c
CHANGED
|
@@ -24,38 +24,14 @@
|
|
|
24
24
|
|
|
25
25
|
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
|
|
26
26
|
|
|
27
|
+
#include "uv.h"
|
|
28
|
+
#include "internal.h"
|
|
29
|
+
|
|
30
|
+
#include <stdatomic.h>
|
|
27
31
|
#include <stdlib.h>
|
|
28
32
|
#include <sched.h>
|
|
29
|
-
#include "../uv-common.h"
|
|
30
33
|
#include "emnapi_common.h"
|
|
31
34
|
|
|
32
|
-
#if defined(__clang__) || \
|
|
33
|
-
defined(__GNUC__) || \
|
|
34
|
-
defined(__INTEL_COMPILER)
|
|
35
|
-
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
|
|
36
|
-
#else
|
|
37
|
-
# define UV_UNUSED(declaration) declaration
|
|
38
|
-
#endif
|
|
39
|
-
|
|
40
|
-
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
|
|
41
|
-
|
|
42
|
-
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
|
43
|
-
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
#ifndef EMNAPI_NEXTTICK_TYPE
|
|
47
|
-
#define EMNAPI_NEXTTICK_TYPE 0
|
|
48
|
-
#endif
|
|
49
|
-
#if EMNAPI_NEXTTICK_TYPE == 0
|
|
50
|
-
EMNAPI_INTERNAL_EXTERN void _emnapi_set_immediate(void (*callback)(void*), void* data);
|
|
51
|
-
#define NEXT_TICK(callback, data) _emnapi_set_immediate((callback), (data))
|
|
52
|
-
#elif EMNAPI_NEXTTICK_TYPE == 1
|
|
53
|
-
EMNAPI_INTERNAL_EXTERN void _emnapi_next_tick(void (*callback)(void*), void* data);
|
|
54
|
-
#define NEXT_TICK(callback, data) _emnapi_next_tick((callback), (data))
|
|
55
|
-
#else
|
|
56
|
-
#error "Invalid EMNAPI_NEXTTICK_TYPE"
|
|
57
|
-
#endif
|
|
58
|
-
|
|
59
35
|
#if EMNAPI_USE_PROXYING
|
|
60
36
|
#include <emscripten/threading.h>
|
|
61
37
|
#include <emscripten/proxying.h>
|
|
@@ -88,36 +64,43 @@ void _emnapi_destroy_proxying_queue(uv_loop_t* loop) {}
|
|
|
88
64
|
|
|
89
65
|
#endif
|
|
90
66
|
|
|
67
|
+
static void uv__async_send(uv_loop_t* loop);
|
|
68
|
+
static void uv__cpu_relax(void);
|
|
69
|
+
|
|
91
70
|
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
|
92
|
-
|
|
93
|
-
handle->type = UV_ASYNC;
|
|
71
|
+
uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
|
|
94
72
|
handle->async_cb = async_cb;
|
|
95
73
|
handle->pending = 0;
|
|
96
|
-
|
|
74
|
+
handle->u.fd = 0; /* This will be used as a busy flag. */
|
|
75
|
+
|
|
76
|
+
uv__queue_insert_tail(&loop->async_handles, &handle->queue);
|
|
77
|
+
uv__handle_start(handle);
|
|
97
78
|
return 0;
|
|
98
79
|
}
|
|
99
80
|
|
|
100
81
|
/* Only call this from the event loop thread. */
|
|
101
|
-
static
|
|
82
|
+
static void uv__async_spin(uv_async_t* handle) {
|
|
83
|
+
_Atomic int* pending;
|
|
84
|
+
_Atomic int* busy;
|
|
102
85
|
int i;
|
|
103
|
-
|
|
86
|
+
|
|
87
|
+
pending = (_Atomic int*) &handle->pending;
|
|
88
|
+
busy = (_Atomic int*) &handle->u.fd;
|
|
89
|
+
|
|
90
|
+
/* Set the pending flag first, so no new events will be added by other
|
|
91
|
+
* threads after this function returns. */
|
|
92
|
+
atomic_store(pending, 1);
|
|
104
93
|
|
|
105
94
|
for (;;) {
|
|
106
|
-
/* 997 is not completely chosen at random. It's a prime number,
|
|
107
|
-
*
|
|
95
|
+
/* 997 is not completely chosen at random. It's a prime number, acyclic by
|
|
96
|
+
* nature, and should therefore hopefully dampen sympathetic resonance.
|
|
108
97
|
*/
|
|
109
98
|
for (i = 0; i < 997; i++) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
* rc=2 -- handle is pending, other thread is done.
|
|
113
|
-
*/
|
|
114
|
-
rc = cmpxchgi(&handle->pending, 2, 0);
|
|
115
|
-
|
|
116
|
-
if (rc != 1)
|
|
117
|
-
return rc;
|
|
99
|
+
if (atomic_load(busy) == 0)
|
|
100
|
+
return;
|
|
118
101
|
|
|
119
102
|
/* Other thread is busy with this handle, spin until it's done. */
|
|
120
|
-
|
|
103
|
+
uv__cpu_relax();
|
|
121
104
|
}
|
|
122
105
|
|
|
123
106
|
/* Yield the CPU. We may have preempted the other thread while it's
|
|
@@ -129,20 +112,23 @@ static int uv__async_spin(uv_async_t* handle) {
|
|
|
129
112
|
}
|
|
130
113
|
|
|
131
114
|
static void uv__async_io(uv_loop_t* loop) {
|
|
132
|
-
|
|
133
|
-
|
|
115
|
+
struct uv__queue queue;
|
|
116
|
+
struct uv__queue* q;
|
|
134
117
|
uv_async_t* h;
|
|
118
|
+
_Atomic int *pending;
|
|
135
119
|
|
|
136
|
-
|
|
137
|
-
while (!
|
|
138
|
-
q =
|
|
139
|
-
h =
|
|
120
|
+
uv__queue_move(&loop->async_handles, &queue);
|
|
121
|
+
while (!uv__queue_empty(&queue)) {
|
|
122
|
+
q = uv__queue_head(&queue);
|
|
123
|
+
h = uv__queue_data(q, uv_async_t, queue);
|
|
140
124
|
|
|
141
|
-
|
|
142
|
-
|
|
125
|
+
uv__queue_remove(q);
|
|
126
|
+
uv__queue_insert_tail(&loop->async_handles, q);
|
|
143
127
|
|
|
144
|
-
|
|
145
|
-
|
|
128
|
+
/* Atomically fetch and clear pending flag */
|
|
129
|
+
pending = (_Atomic int*) &h->pending;
|
|
130
|
+
if (atomic_exchange(pending, 0) == 0)
|
|
131
|
+
continue;
|
|
146
132
|
|
|
147
133
|
if (h->async_cb == NULL)
|
|
148
134
|
continue;
|
|
@@ -195,28 +181,45 @@ static void uv__async_send(uv_loop_t* loop) {
|
|
|
195
181
|
#define ACCESS_ONCE(type, var) (*(volatile type*) &(var))
|
|
196
182
|
|
|
197
183
|
int uv_async_send(uv_async_t* handle) {
|
|
184
|
+
_Atomic int* pending;
|
|
185
|
+
_Atomic int* busy;
|
|
186
|
+
|
|
187
|
+
pending = (_Atomic int*) &handle->pending;
|
|
188
|
+
busy = (_Atomic int*) &handle->u.fd;
|
|
189
|
+
|
|
198
190
|
/* Do a cheap read first. */
|
|
199
|
-
if (
|
|
191
|
+
if (atomic_load_explicit(pending, memory_order_relaxed) != 0)
|
|
200
192
|
return 0;
|
|
201
193
|
|
|
202
|
-
/*
|
|
203
|
-
|
|
204
|
-
return 0;
|
|
194
|
+
/* Set the loop to busy. */
|
|
195
|
+
atomic_fetch_add(busy, 1);
|
|
205
196
|
|
|
206
197
|
/* Wake up the other thread's event loop. */
|
|
207
|
-
|
|
198
|
+
if (atomic_exchange(pending, 1) == 0)
|
|
199
|
+
uv__async_send(handle->loop);
|
|
208
200
|
|
|
209
|
-
/*
|
|
210
|
-
|
|
211
|
-
abort();
|
|
201
|
+
/* Set the loop to not-busy. */
|
|
202
|
+
atomic_fetch_add(busy, -1);
|
|
212
203
|
|
|
213
204
|
return 0;
|
|
214
205
|
}
|
|
215
206
|
|
|
216
207
|
void uv__async_close(uv_async_t* handle) {
|
|
217
208
|
uv__async_spin(handle);
|
|
218
|
-
|
|
219
|
-
|
|
209
|
+
uv__queue_remove(&handle->queue);
|
|
210
|
+
uv__handle_stop(handle);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static void uv__cpu_relax(void) {
|
|
214
|
+
#if defined(__i386__) || defined(__x86_64__)
|
|
215
|
+
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
|
|
216
|
+
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
|
217
|
+
__asm__ __volatile__ ("yield" ::: "memory");
|
|
218
|
+
#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__)
|
|
219
|
+
__asm volatile ("" : : : "memory");
|
|
220
|
+
#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__))
|
|
221
|
+
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
|
|
222
|
+
#endif
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
#endif
|
package/src/uv/unix/core.c
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
|
|
2
2
|
|
|
3
|
+
#include "uv.h"
|
|
4
|
+
#include "internal.h"
|
|
3
5
|
#include <errno.h>
|
|
4
6
|
#include <time.h>
|
|
5
|
-
|
|
7
|
+
|
|
8
|
+
uint64_t uv_hrtime(void) {
|
|
9
|
+
return uv__hrtime(UV_CLOCK_PRECISE);
|
|
10
|
+
}
|
|
6
11
|
|
|
7
12
|
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
|
13
|
+
assert(!uv__is_closing(handle));
|
|
14
|
+
|
|
15
|
+
handle->flags |= UV_HANDLE_CLOSING;
|
|
8
16
|
handle->close_cb = close_cb;
|
|
9
17
|
|
|
10
18
|
switch (handle->type) {
|
|
@@ -14,6 +22,33 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
|
|
14
22
|
default:
|
|
15
23
|
assert(0);
|
|
16
24
|
}
|
|
25
|
+
|
|
26
|
+
uv__make_close_pending(handle);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static void uv__finish_close(uv_handle_t* handle) {
|
|
30
|
+
assert(handle->flags & UV_HANDLE_CLOSING);
|
|
31
|
+
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
|
32
|
+
handle->flags |= UV_HANDLE_CLOSED;
|
|
33
|
+
|
|
34
|
+
uv__handle_unref(handle);
|
|
35
|
+
uv__queue_remove(&handle->handle_queue);
|
|
36
|
+
|
|
37
|
+
if (handle->close_cb) {
|
|
38
|
+
handle->close_cb(handle);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
void uv__make_close_pending(uv_handle_t* handle) {
|
|
43
|
+
assert(handle->flags & UV_HANDLE_CLOSING);
|
|
44
|
+
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
|
45
|
+
// handle->next_closing = handle->loop->closing_handles;
|
|
46
|
+
// handle->loop->closing_handles = handle;
|
|
47
|
+
NEXT_TICK(((void (*)(void *))uv__finish_close), handle);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
int uv_is_closing(const uv_handle_t* handle) {
|
|
51
|
+
return uv__is_closing(handle);
|
|
17
52
|
}
|
|
18
53
|
|
|
19
54
|
int nanosleep(const struct timespec *, struct timespec *);
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
* of this software and associated documentation files (the "Software"), to
|
|
5
|
+
* deal in the Software without restriction, including without limitation the
|
|
6
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
7
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
* furnished to do so, subject to the following conditions:
|
|
9
|
+
*
|
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
|
11
|
+
* all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
19
|
+
* IN THE SOFTWARE.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#ifndef UV_UNIX_INTERNAL_H_
|
|
23
|
+
#define UV_UNIX_INTERNAL_H_
|
|
24
|
+
|
|
25
|
+
#include "../uv-common.h"
|
|
26
|
+
#include "emnapi_common.h"
|
|
27
|
+
#include <stdint.h>
|
|
28
|
+
|
|
29
|
+
#ifndef EMNAPI_NEXTTICK_TYPE
|
|
30
|
+
#define EMNAPI_NEXTTICK_TYPE 0
|
|
31
|
+
#endif
|
|
32
|
+
#if EMNAPI_NEXTTICK_TYPE == 0
|
|
33
|
+
EMNAPI_INTERNAL_EXTERN void _emnapi_set_immediate(void (*callback)(void*), void* data);
|
|
34
|
+
#define NEXT_TICK(callback, data) _emnapi_set_immediate((callback), (data))
|
|
35
|
+
#elif EMNAPI_NEXTTICK_TYPE == 1
|
|
36
|
+
EMNAPI_INTERNAL_EXTERN void _emnapi_next_tick(void (*callback)(void*), void* data);
|
|
37
|
+
#define NEXT_TICK(callback, data) _emnapi_next_tick((callback), (data))
|
|
38
|
+
#else
|
|
39
|
+
#error "Invalid EMNAPI_NEXTTICK_TYPE"
|
|
40
|
+
#endif
|
|
41
|
+
|
|
42
|
+
typedef enum {
|
|
43
|
+
UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
|
|
44
|
+
UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
|
|
45
|
+
} uv_clocktype_t;
|
|
46
|
+
|
|
47
|
+
uint64_t uv__hrtime(uv_clocktype_t type);
|
|
48
|
+
|
|
49
|
+
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
|
|
50
|
+
void uv__async_close(uv_async_t* handle);
|
|
51
|
+
void uv__make_close_pending(uv_handle_t* handle);
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
#endif /* UV_UNIX_INTERNAL_H_ */
|
package/src/uv/unix/loop.c
CHANGED
|
@@ -1,16 +1,38 @@
|
|
|
1
1
|
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
|
|
2
2
|
|
|
3
3
|
#include "../uv-common.h"
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <string.h>
|
|
4
6
|
|
|
5
7
|
int _emnapi_create_proxying_queue(uv_loop_t* loop);
|
|
6
8
|
void _emnapi_destroy_proxying_queue(uv_loop_t* loop);
|
|
7
9
|
|
|
8
10
|
int uv_loop_init(uv_loop_t* loop) {
|
|
11
|
+
uv__loop_internal_fields_t* lfields;
|
|
12
|
+
void* saved_data;
|
|
9
13
|
int err;
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
|
|
15
|
+
saved_data = loop->data;
|
|
16
|
+
memset(loop, 0, sizeof(*loop));
|
|
17
|
+
loop->data = saved_data;
|
|
18
|
+
|
|
19
|
+
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
|
|
20
|
+
if (lfields == NULL)
|
|
21
|
+
return ENOMEM;
|
|
22
|
+
loop->internal_fields = lfields;
|
|
23
|
+
|
|
24
|
+
err = uv_mutex_init(&lfields->loop_metrics.lock);
|
|
25
|
+
if (err)
|
|
26
|
+
goto fail_metrics_mutex_init;
|
|
27
|
+
memset(&lfields->loop_metrics.metrics,
|
|
28
|
+
0,
|
|
29
|
+
sizeof(lfields->loop_metrics.metrics));
|
|
30
|
+
|
|
31
|
+
uv__queue_init(&loop->wq);
|
|
32
|
+
uv__queue_init(&loop->async_handles);
|
|
33
|
+
uv__queue_init(&loop->handle_queue);
|
|
12
34
|
err = _emnapi_create_proxying_queue(loop);
|
|
13
|
-
if (err)
|
|
35
|
+
if (err) goto fail_proxying_queue_init;
|
|
14
36
|
err = uv_mutex_init(&loop->wq_mutex);
|
|
15
37
|
if (err) goto fail_mutex_init;
|
|
16
38
|
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
|
|
@@ -21,16 +43,30 @@ fail_async_init:
|
|
|
21
43
|
uv_mutex_destroy(&loop->wq_mutex);
|
|
22
44
|
|
|
23
45
|
fail_mutex_init:
|
|
46
|
+
|
|
47
|
+
fail_proxying_queue_init:
|
|
48
|
+
|
|
49
|
+
fail_metrics_mutex_init:
|
|
50
|
+
uv__free(lfields);
|
|
51
|
+
loop->internal_fields = NULL;
|
|
52
|
+
|
|
24
53
|
return err;
|
|
25
54
|
}
|
|
26
55
|
|
|
27
56
|
void uv__loop_close(uv_loop_t* loop) {
|
|
57
|
+
uv__loop_internal_fields_t* lfields;
|
|
58
|
+
|
|
28
59
|
uv_mutex_lock(&loop->wq_mutex);
|
|
29
|
-
assert(
|
|
60
|
+
assert(uv__queue_empty(&loop->wq) && "thread pool work queue not empty!");
|
|
30
61
|
assert(!uv__has_active_reqs(loop));
|
|
31
62
|
_emnapi_destroy_proxying_queue(loop);
|
|
32
63
|
uv_mutex_unlock(&loop->wq_mutex);
|
|
33
64
|
uv_mutex_destroy(&loop->wq_mutex);
|
|
65
|
+
|
|
66
|
+
lfields = uv__get_internal_fields(loop);
|
|
67
|
+
uv_mutex_destroy(&lfields->loop_metrics.lock);
|
|
68
|
+
uv__free(lfields);
|
|
69
|
+
loop->internal_fields = NULL;
|
|
34
70
|
}
|
|
35
71
|
|
|
36
72
|
#endif
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* Copyright libuv project contributors. All rights reserved.
|
|
2
|
+
*
|
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
* of this software and associated documentation files (the "Software"), to
|
|
5
|
+
* deal in the Software without restriction, including without limitation the
|
|
6
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
7
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
* furnished to do so, subject to the following conditions:
|
|
9
|
+
*
|
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
|
11
|
+
* all copies or substantial portions of the Software.
|
|
12
|
+
*
|
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
19
|
+
* IN THE SOFTWARE.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
#if !defined(__wasm__) || (defined(__EMSCRIPTEN__) || defined(__wasi__))
|
|
23
|
+
|
|
24
|
+
#include "uv.h"
|
|
25
|
+
#include "internal.h"
|
|
26
|
+
|
|
27
|
+
#include <stdint.h>
|
|
28
|
+
#include <stdlib.h>
|
|
29
|
+
#include <time.h>
|
|
30
|
+
|
|
31
|
+
uint64_t uv__hrtime(uv_clocktype_t type) {
|
|
32
|
+
struct timespec t;
|
|
33
|
+
|
|
34
|
+
if (clock_gettime(CLOCK_MONOTONIC, &t))
|
|
35
|
+
abort();
|
|
36
|
+
|
|
37
|
+
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#endif
|