emnapi 1.2.0 → 1.3.1
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/README.md +7 -18
- package/common.gypi +1 -0
- package/dist/library_napi.js +130 -41
- package/emnapi.gyp +4 -0
- package/include/node/emnapi.h +2 -2
- 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 +25 -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/index.js +1 -0
- 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
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
#include <stdatomic.h>
|
|
6
6
|
#include <pthread.h>
|
|
7
7
|
#include <errno.h>
|
|
8
|
-
#include "uv/queue.h"
|
|
9
|
-
|
|
10
8
|
#include "uv.h"
|
|
9
|
+
#include "uv/queue.h"
|
|
11
10
|
|
|
12
11
|
EXTERN_C_START
|
|
13
12
|
|
|
@@ -21,7 +20,7 @@ static const unsigned int kMaxIterationCount = 1000;
|
|
|
21
20
|
|
|
22
21
|
struct data_queue_node {
|
|
23
22
|
void* data;
|
|
24
|
-
|
|
23
|
+
struct uv__queue q;
|
|
25
24
|
};
|
|
26
25
|
|
|
27
26
|
struct napi_threadsafe_function__ {
|
|
@@ -30,7 +29,7 @@ struct napi_threadsafe_function__ {
|
|
|
30
29
|
pthread_mutex_t mutex;
|
|
31
30
|
pthread_cond_t* cond;
|
|
32
31
|
size_t queue_size;
|
|
33
|
-
|
|
32
|
+
struct uv__queue queue;
|
|
34
33
|
uv_async_t async;
|
|
35
34
|
size_t thread_count;
|
|
36
35
|
bool is_closing;
|
|
@@ -92,7 +91,7 @@ _emnapi_tsfn_create(napi_env env,
|
|
|
92
91
|
pthread_mutex_init(&ts_fn->mutex, NULL);
|
|
93
92
|
ts_fn->cond = NULL;
|
|
94
93
|
ts_fn->queue_size = 0;
|
|
95
|
-
|
|
94
|
+
uv__queue_init(&ts_fn->queue);
|
|
96
95
|
ts_fn->thread_count = initial_thread_count;
|
|
97
96
|
ts_fn->is_closing = false;
|
|
98
97
|
ts_fn->dispatch_state = kDispatchIdle;
|
|
@@ -125,13 +124,13 @@ static void _emnapi_tsfn_destroy(napi_threadsafe_function func) {
|
|
|
125
124
|
func->cond = NULL;
|
|
126
125
|
}
|
|
127
126
|
|
|
128
|
-
|
|
127
|
+
struct uv__queue* tmp;
|
|
129
128
|
struct data_queue_node* node;
|
|
130
|
-
|
|
131
|
-
node =
|
|
129
|
+
uv__queue_foreach(tmp, &func->queue) {
|
|
130
|
+
node = uv__queue_data(tmp, struct data_queue_node, q);
|
|
132
131
|
free(node);
|
|
133
132
|
}
|
|
134
|
-
|
|
133
|
+
uv__queue_init(&func->queue);
|
|
135
134
|
|
|
136
135
|
if (func->ref != NULL) {
|
|
137
136
|
EMNAPI_ASSERT_CALL(napi_delete_reference(func->env, func->ref));
|
|
@@ -187,14 +186,14 @@ static napi_status _emnapi_tsfn_init(napi_threadsafe_function func) {
|
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
static void _emnapi_tsfn_empty_queue_and_delete(napi_threadsafe_function func) {
|
|
190
|
-
while (!
|
|
191
|
-
|
|
192
|
-
struct data_queue_node* node =
|
|
189
|
+
while (!uv__queue_empty(&func->queue)) {
|
|
190
|
+
struct uv__queue* q = uv__queue_head(&func->queue);
|
|
191
|
+
struct data_queue_node* node = uv__queue_data(q, struct data_queue_node, q);
|
|
193
192
|
|
|
194
193
|
func->call_js_cb(NULL, NULL, func->context, node->data);
|
|
195
194
|
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
uv__queue_remove(q);
|
|
196
|
+
uv__queue_init(q);
|
|
198
197
|
func->queue_size--;
|
|
199
198
|
free(node);
|
|
200
199
|
}
|
|
@@ -295,10 +294,10 @@ static bool _emnapi_tsfn_dispatch_one(napi_threadsafe_function func) {
|
|
|
295
294
|
} else {
|
|
296
295
|
size_t size = func->queue_size;
|
|
297
296
|
if (size > 0) {
|
|
298
|
-
|
|
299
|
-
struct data_queue_node* node =
|
|
300
|
-
|
|
301
|
-
|
|
297
|
+
struct uv__queue* q = uv__queue_head(&func->queue);
|
|
298
|
+
struct data_queue_node* node = uv__queue_data(q, struct data_queue_node, q);
|
|
299
|
+
uv__queue_remove(q);
|
|
300
|
+
uv__queue_init(q);
|
|
302
301
|
func->queue_size--;
|
|
303
302
|
data = node->data;
|
|
304
303
|
free(node);
|
|
@@ -519,7 +518,7 @@ napi_call_threadsafe_function(napi_threadsafe_function func,
|
|
|
519
518
|
return napi_generic_failure;
|
|
520
519
|
}
|
|
521
520
|
queue_node->data = data;
|
|
522
|
-
|
|
521
|
+
uv__queue_insert_tail(&func->queue, &queue_node->q);
|
|
523
522
|
func->queue_size++;
|
|
524
523
|
_emnapi_tsfn_send(func);
|
|
525
524
|
pthread_mutex_unlock(&func->mutex);
|
|
@@ -584,7 +583,7 @@ napi_release_threadsafe_function(napi_threadsafe_function func,
|
|
|
584
583
|
}
|
|
585
584
|
|
|
586
585
|
napi_status
|
|
587
|
-
napi_unref_threadsafe_function(
|
|
586
|
+
napi_unref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function func) {
|
|
588
587
|
#if EMNAPI_HAVE_THREADS
|
|
589
588
|
if (func->async_ref) {
|
|
590
589
|
EMNAPI_KEEPALIVE_POP();
|
|
@@ -598,7 +597,7 @@ napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
|
|
|
598
597
|
}
|
|
599
598
|
|
|
600
599
|
napi_status
|
|
601
|
-
napi_ref_threadsafe_function(
|
|
600
|
+
napi_ref_threadsafe_function(node_api_basic_env env, napi_threadsafe_function func) {
|
|
602
601
|
#if EMNAPI_HAVE_THREADS
|
|
603
602
|
if (!func->async_ref) {
|
|
604
603
|
EMNAPI_KEEPALIVE_PUSH();
|
package/src/uv/queue.h
CHANGED
|
@@ -18,91 +18,73 @@
|
|
|
18
18
|
|
|
19
19
|
#include <stddef.h>
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
#define
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
} \
|
|
90
|
-
while (0)
|
|
91
|
-
|
|
92
|
-
#define QUEUE_INSERT_TAIL(h, q) \
|
|
93
|
-
do { \
|
|
94
|
-
QUEUE_NEXT(q) = (h); \
|
|
95
|
-
QUEUE_PREV(q) = QUEUE_PREV(h); \
|
|
96
|
-
QUEUE_PREV_NEXT(q) = (q); \
|
|
97
|
-
QUEUE_PREV(h) = (q); \
|
|
98
|
-
} \
|
|
99
|
-
while (0)
|
|
100
|
-
|
|
101
|
-
#define QUEUE_REMOVE(q) \
|
|
102
|
-
do { \
|
|
103
|
-
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
|
|
104
|
-
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
|
|
105
|
-
} \
|
|
106
|
-
while (0)
|
|
21
|
+
#define uv__queue_data(pointer, type, field) \
|
|
22
|
+
((type*) ((char*) (pointer) - offsetof(type, field)))
|
|
23
|
+
|
|
24
|
+
#define uv__queue_foreach(q, h) \
|
|
25
|
+
for ((q) = (h)->next; (q) != (h); (q) = (q)->next)
|
|
26
|
+
|
|
27
|
+
static inline void uv__queue_init(struct uv__queue* q) {
|
|
28
|
+
q->next = q;
|
|
29
|
+
q->prev = q;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static inline int uv__queue_empty(const struct uv__queue* q) {
|
|
33
|
+
return q == q->next;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
static inline struct uv__queue* uv__queue_head(const struct uv__queue* q) {
|
|
37
|
+
return q->next;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static inline struct uv__queue* uv__queue_next(const struct uv__queue* q) {
|
|
41
|
+
return q->next;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static inline void uv__queue_add(struct uv__queue* h, struct uv__queue* n) {
|
|
45
|
+
h->prev->next = n->next;
|
|
46
|
+
n->next->prev = h->prev;
|
|
47
|
+
h->prev = n->prev;
|
|
48
|
+
h->prev->next = h;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static inline void uv__queue_split(struct uv__queue* h,
|
|
52
|
+
struct uv__queue* q,
|
|
53
|
+
struct uv__queue* n) {
|
|
54
|
+
n->prev = h->prev;
|
|
55
|
+
n->prev->next = n;
|
|
56
|
+
n->next = q;
|
|
57
|
+
h->prev = q->prev;
|
|
58
|
+
h->prev->next = h;
|
|
59
|
+
q->prev = n;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static inline void uv__queue_move(struct uv__queue* h, struct uv__queue* n) {
|
|
63
|
+
if (uv__queue_empty(h))
|
|
64
|
+
uv__queue_init(n);
|
|
65
|
+
else
|
|
66
|
+
uv__queue_split(h, h->next, n);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static inline void uv__queue_insert_head(struct uv__queue* h,
|
|
70
|
+
struct uv__queue* q) {
|
|
71
|
+
q->next = h->next;
|
|
72
|
+
q->prev = h;
|
|
73
|
+
q->next->prev = q;
|
|
74
|
+
h->next = q;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static inline void uv__queue_insert_tail(struct uv__queue* h,
|
|
78
|
+
struct uv__queue* q) {
|
|
79
|
+
q->next = h;
|
|
80
|
+
q->prev = h->prev;
|
|
81
|
+
q->prev->next = q;
|
|
82
|
+
h->prev = q;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static inline void uv__queue_remove(struct uv__queue* q) {
|
|
86
|
+
q->prev->next = q->next;
|
|
87
|
+
q->next->prev = q->prev;
|
|
88
|
+
}
|
|
107
89
|
|
|
108
90
|
#endif /* QUEUE_H_ */
|
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;
|