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.
Files changed (41) hide show
  1. package/CMakeLists.txt +13 -3
  2. package/dist/library_napi.js +54 -33
  3. package/emnapi.gyp +3 -0
  4. package/include/node/emnapi.h +1 -1
  5. package/include/node/js_native_api.h +30 -25
  6. package/include/node/js_native_api_types.h +13 -9
  7. package/include/node/node_api.h +13 -13
  8. package/include/node/uv/threadpool.h +1 -1
  9. package/include/node/uv/unix.h +4 -0
  10. package/include/node/uv.h +49 -6
  11. package/lib/wasm32/libemnapi.a +0 -0
  12. package/lib/wasm32-emscripten/libemnapi-mt.a +0 -0
  13. package/lib/wasm32-emscripten/libemnapi.a +0 -0
  14. package/lib/wasm32-wasi/libemnapi.a +0 -0
  15. package/lib/wasm32-wasi-threads/libemnapi-basic-mt.a +0 -0
  16. package/lib/wasm32-wasi-threads/libemnapi-basic.a +0 -0
  17. package/lib/wasm32-wasi-threads/libemnapi-mt.a +0 -0
  18. package/lib/wasm32-wasi-threads/libemnapi.a +0 -0
  19. package/lib/wasm32-wasip1/libemnapi.a +0 -0
  20. package/lib/wasm32-wasip1-threads/libemnapi-basic-mt.a +0 -0
  21. package/lib/wasm32-wasip1-threads/libemnapi-basic.a +0 -0
  22. package/lib/wasm32-wasip1-threads/libemnapi-mt.a +0 -0
  23. package/lib/wasm32-wasip1-threads/libemnapi.a +0 -0
  24. package/lib/wasm64-emscripten/libemnapi-mt.a +0 -0
  25. package/lib/wasm64-emscripten/libemnapi.a +0 -0
  26. package/package.json +1 -1
  27. package/src/async_cleanup_hook.c +1 -1
  28. package/src/async_work.c +2 -2
  29. package/src/emnapi_internal.h +2 -2
  30. package/src/js_native_api.c +2 -1
  31. package/src/node_api.c +5 -5
  32. package/src/threadsafe_function.c +20 -21
  33. package/src/uv/queue.h +68 -86
  34. package/src/uv/threadpool.c +58 -40
  35. package/src/uv/unix/async.c +67 -64
  36. package/src/uv/unix/core.c +36 -1
  37. package/src/uv/unix/internal.h +54 -0
  38. package/src/uv/unix/loop.c +40 -4
  39. package/src/uv/unix/posix-hrtime.c +40 -0
  40. package/src/uv/uv-common.c +123 -7
  41. package/src/uv/uv-common.h +137 -9
@@ -19,7 +19,7 @@
19
19
  * IN THE SOFTWARE.
20
20
  */
21
21
 
22
- // from libuv 1.43.0
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 QUEUE exit_message;
47
- static QUEUE wq;
48
- static QUEUE run_slow_work_message;
49
- static QUEUE slow_io_pending_wq;
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)(QUEUE* w, enum uv__work_kind kind),
64
- QUEUE* w,
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
- QUEUE* q;
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 (QUEUE_EMPTY(&wq) ||
91
- (QUEUE_HEAD(&wq) == &run_slow_work_message &&
92
- QUEUE_NEXT(&run_slow_work_message) == &wq &&
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 = QUEUE_HEAD(&wq);
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
- QUEUE_REMOVE(q);
107
- QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
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
- QUEUE_INSERT_TAIL(&wq, q);
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 (QUEUE_EMPTY(&slow_io_pending_wq))
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 = QUEUE_HEAD(&slow_io_pending_wq);
127
- QUEUE_REMOVE(q);
128
- QUEUE_INIT(q);
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 (!QUEUE_EMPTY(&slow_io_pending_wq)) {
132
- QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
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 = QUEUE_DATA(q, struct uv__work, wq);
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
- QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
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(QUEUE* q, enum uv__work_kind kind) {
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
- // QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
167
- // if (!QUEUE_EMPTY(&run_slow_work_message)) {
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
- QUEUE_INSERT_TAIL(&wq, q);
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
- QUEUE_INIT(&wq);
258
- QUEUE_INIT(&slow_io_pending_wq);
259
- QUEUE_INIT(&run_slow_work_message);
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 = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
338
+ cancelled = !uv__queue_empty(&w->wq) && w->work != NULL;
338
339
  if (cancelled)
339
- QUEUE_REMOVE(&w->wq);
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
- QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
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
- QUEUE* q;
361
- QUEUE wq;
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
- QUEUE_MOVE(&loop->wq, &wq);
368
+ uv__queue_move(&loop->wq, &wq);
367
369
  uv_mutex_unlock(&loop->wq_mutex);
368
370
 
369
- while (!QUEUE_EMPTY(&wq)) {
370
- q = QUEUE_HEAD(&wq);
371
- QUEUE_REMOVE(q);
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, req);
409
+ uv__req_unregister(req->loop);
392
410
 
393
411
  if (req->after_work_cb == NULL)
394
412
  return;
@@ -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
- handle->loop = loop;
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
- QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
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 int uv__async_spin(uv_async_t* handle) {
82
+ static void uv__async_spin(uv_async_t* handle) {
83
+ _Atomic int* pending;
84
+ _Atomic int* busy;
102
85
  int i;
103
- int rc;
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, acyclical
107
- * by nature, and should therefore hopefully dampen sympathetic resonance.
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
- /* rc=0 -- handle is not pending.
111
- * rc=1 -- handle is pending, other thread is still working with it.
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
- // cpu_relax();
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
- QUEUE queue;
133
- QUEUE* q;
115
+ struct uv__queue queue;
116
+ struct uv__queue* q;
134
117
  uv_async_t* h;
118
+ _Atomic int *pending;
135
119
 
136
- QUEUE_MOVE(&loop->async_handles, &queue);
137
- while (!QUEUE_EMPTY(&queue)) {
138
- q = QUEUE_HEAD(&queue);
139
- h = QUEUE_DATA(q, uv_async_t, queue);
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
- QUEUE_REMOVE(q);
142
- QUEUE_INSERT_TAIL(&loop->async_handles, q);
125
+ uv__queue_remove(q);
126
+ uv__queue_insert_tail(&loop->async_handles, q);
143
127
 
144
- if (0 == uv__async_spin(h))
145
- continue; /* Not pending. */
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 (ACCESS_ONCE(int, handle->pending) != 0)
191
+ if (atomic_load_explicit(pending, memory_order_relaxed) != 0)
200
192
  return 0;
201
193
 
202
- /* Tell the other thread we're busy with the handle. */
203
- if (cmpxchgi(&handle->pending, 0, 1) != 0)
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
- uv__async_send(handle->loop);
198
+ if (atomic_exchange(pending, 1) == 0)
199
+ uv__async_send(handle->loop);
208
200
 
209
- /* Tell the other thread we're done. */
210
- if (cmpxchgi(&handle->pending, 1, 2) != 1)
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
- QUEUE_REMOVE(&handle->queue);
219
- NEXT_TICK(((void (*)(void *))handle->close_cb), handle);
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
@@ -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
- #include "../uv-common.h"
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_ */
@@ -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
- QUEUE_INIT(&loop->wq);
11
- QUEUE_INIT(&loop->async_handles);
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) return 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(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
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