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
package/include/node/uv.h CHANGED
@@ -3,13 +3,21 @@
3
3
 
4
4
  #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)
5
5
 
6
- #include <stddef.h>
7
- #include "uv/unix.h"
8
-
9
6
  #ifdef __cplusplus
10
7
  extern "C" {
11
8
  #endif
12
9
 
10
+ #include <stddef.h>
11
+ #include <stdint.h>
12
+
13
+ /* Internal type, do not use. */
14
+ struct uv__queue {
15
+ struct uv__queue* next;
16
+ struct uv__queue* prev;
17
+ };
18
+
19
+ #include "uv/unix.h"
20
+
13
21
  #define UV_EXTERN /* nothing */
14
22
 
15
23
  typedef enum {
@@ -29,6 +37,8 @@ typedef struct uv_work_s uv_work_t;
29
37
  typedef struct uv_handle_s uv_handle_t;
30
38
  typedef struct uv_async_s uv_async_t;
31
39
 
40
+ typedef struct uv_metrics_s uv_metrics_t;
41
+
32
42
  typedef void (*uv_work_cb)(uv_work_t* req);
33
43
  typedef void (*uv_after_work_cb)(uv_work_t* req, int status);
34
44
 
@@ -40,10 +50,22 @@ struct uv_req_s {
40
50
  UV_REQ_FIELDS
41
51
  };
42
52
 
53
+ typedef void* (*uv_malloc_func)(size_t size);
54
+ typedef void* (*uv_realloc_func)(void* ptr, size_t size);
55
+ typedef void* (*uv_calloc_func)(size_t count, size_t size);
56
+ typedef void (*uv_free_func)(void* ptr);
57
+
43
58
  UV_EXTERN void uv_library_shutdown(void);
59
+
60
+ UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
61
+ uv_realloc_func realloc_func,
62
+ uv_calloc_func calloc_func,
63
+ uv_free_func free_func);
64
+
44
65
  UV_EXTERN uv_loop_t* uv_default_loop(void);
45
66
  UV_EXTERN int uv_loop_init(uv_loop_t* loop);
46
67
  UV_EXTERN int uv_loop_close(uv_loop_t* loop);
68
+ UV_EXTERN uint64_t uv_hrtime(void);
47
69
  UV_EXTERN void uv_sleep(unsigned int msec);
48
70
 
49
71
  UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
@@ -111,6 +133,12 @@ typedef void (*uv_async_cb)(uv_async_t* handle);
111
133
  uv_loop_t* loop; \
112
134
  uv_handle_type type; \
113
135
  uv_close_cb close_cb; \
136
+ struct uv__queue handle_queue; \
137
+ union { \
138
+ int fd; \
139
+ void* reserved[4]; \
140
+ } u; \
141
+ UV_HANDLE_PRIVATE_FIELDS \
114
142
 
115
143
  struct uv_handle_s {
116
144
  UV_HANDLE_FIELDS
@@ -119,7 +147,7 @@ struct uv_handle_s {
119
147
  struct uv_async_s {
120
148
  UV_HANDLE_FIELDS
121
149
  uv_async_cb async_cb;
122
- void* queue[2];
150
+ struct uv__queue queue;
123
151
  int pending;
124
152
  };
125
153
 
@@ -129,18 +157,33 @@ UV_EXTERN int uv_async_init(uv_loop_t*,
129
157
  UV_EXTERN int uv_async_send(uv_async_t* async);
130
158
 
131
159
  UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
160
+ UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
161
+
162
+ struct uv_metrics_s {
163
+ uint64_t loop_count;
164
+ uint64_t events;
165
+ uint64_t events_waiting;
166
+ /* private */
167
+ uint64_t* reserved[13];
168
+ };
169
+
170
+ UV_EXTERN int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics);
171
+ UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop);
132
172
 
133
173
  struct uv_loop_s {
134
174
  void* data;
175
+ unsigned int active_handles;
176
+ struct uv__queue handle_queue;
135
177
  union {
136
178
  void* unused;
137
179
  unsigned int count;
138
180
  } active_reqs;
139
- void* wq[2];
181
+ void* internal_fields;
140
182
 
183
+ struct uv__queue wq;
141
184
  uv_mutex_t wq_mutex;
142
185
  uv_async_t wq_async;
143
- void* async_handles[2];
186
+ struct uv__queue async_handles;
144
187
  void* em_queue;
145
188
  };
146
189
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emnapi",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Node-API implementation for Emscripten",
5
5
  "main": "index.js",
6
6
  "gypfile": false,
@@ -101,7 +101,7 @@ _emnapi_ach_handle_delete(napi_async_cleanup_hook_handle handle) {
101
101
  }
102
102
 
103
103
  napi_status
104
- napi_add_async_cleanup_hook(napi_env env,
104
+ napi_add_async_cleanup_hook(node_api_basic_env env,
105
105
  napi_async_cleanup_hook hook,
106
106
  void* arg,
107
107
  napi_async_cleanup_hook_handle* remove_handle) {
package/src/async_work.c CHANGED
@@ -198,7 +198,7 @@ napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
198
198
  #endif
199
199
  }
200
200
 
201
- napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
201
+ napi_status napi_queue_async_work(node_api_basic_env env, napi_async_work work) {
202
202
  #if EMNAPI_HAVE_THREADS
203
203
  CHECK_ENV(env);
204
204
  CHECK_ARG(env, work);
@@ -220,7 +220,7 @@ napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
220
220
  } \
221
221
  } while (0)
222
222
 
223
- napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
223
+ napi_status napi_cancel_async_work(node_api_basic_env env, napi_async_work work) {
224
224
  #if EMNAPI_HAVE_THREADS
225
225
  CHECK_ENV(env);
226
226
  CHECK_ARG(env, work);
@@ -72,11 +72,11 @@ EXTERN_C_END
72
72
 
73
73
  EXTERN_C_START
74
74
 
75
- EMNAPI_INTERNAL_EXTERN napi_status napi_set_last_error(node_api_nogc_env env,
75
+ EMNAPI_INTERNAL_EXTERN napi_status napi_set_last_error(node_api_basic_env env,
76
76
  napi_status error_code,
77
77
  uint32_t engine_error_code,
78
78
  void* engine_reserved);
79
- EMNAPI_INTERNAL_EXTERN napi_status napi_clear_last_error(node_api_nogc_env env);
79
+ EMNAPI_INTERNAL_EXTERN napi_status napi_clear_last_error(node_api_basic_env env);
80
80
 
81
81
  #ifdef __EMSCRIPTEN__
82
82
  #if __EMSCRIPTEN_major__ * 10000 + __EMSCRIPTEN_minor__ * 100 + __EMSCRIPTEN_tiny__ >= 30114 // NOLINT
@@ -35,8 +35,9 @@ EMNAPI_INTERNAL_EXTERN void _emnapi_get_last_error_info(napi_env env,
35
35
  void** engine_reserved);
36
36
 
37
37
  napi_status napi_get_last_error_info(
38
- napi_env env, const napi_extended_error_info** result) {
38
+ node_api_basic_env basic_env, const napi_extended_error_info** result) {
39
39
  static napi_extended_error_info last_error;
40
+ napi_env env = (napi_env) basic_env;
40
41
  CHECK_ENV(env);
41
42
  CHECK_ARG(env, result);
42
43
 
package/src/node_api.c CHANGED
@@ -1,7 +1,7 @@
1
1
  #include "node_api.h"
2
2
  #include "emnapi_internal.h"
3
3
 
4
- #if EMNAPI_HAVE_THREADS
4
+ #if EMNAPI_HAVE_THREADS && !defined(EMNAPI_DISABLE_UV)
5
5
  #include "uv.h"
6
6
  #endif
7
7
 
@@ -12,7 +12,7 @@ EMNAPI_INTERNAL_EXTERN void _emnapi_get_node_version(uint32_t* major,
12
12
  uint32_t* patch);
13
13
 
14
14
  napi_status
15
- napi_get_node_version(napi_env env,
15
+ napi_get_node_version(node_api_basic_env env,
16
16
  const napi_node_version** version) {
17
17
  CHECK_ENV(env);
18
18
  CHECK_ARG(env, version);
@@ -29,9 +29,9 @@ napi_get_node_version(napi_env env,
29
29
  return napi_clear_last_error(env);
30
30
  }
31
31
 
32
- napi_status napi_get_uv_event_loop(napi_env env,
32
+ napi_status napi_get_uv_event_loop(node_api_basic_env env,
33
33
  struct uv_loop_s** loop) {
34
- #if EMNAPI_HAVE_THREADS
34
+ #if EMNAPI_HAVE_THREADS && !defined(EMNAPI_DISABLE_UV)
35
35
  CHECK_ENV(env);
36
36
  CHECK_ARG(env, loop);
37
37
  // Though this is fake libuv loop
@@ -44,7 +44,7 @@ napi_status napi_get_uv_event_loop(napi_env env,
44
44
 
45
45
  EMNAPI_INTERNAL_EXTERN int _emnapi_get_filename(napi_env env, char* buf, int len);
46
46
 
47
- napi_status node_api_get_module_file_name(napi_env env,
47
+ napi_status node_api_get_module_file_name(node_api_basic_env env,
48
48
  const char** result) {
49
49
  CHECK_ENV(env);
50
50
  CHECK_ARG(env, result);
@@ -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
- void* q[2];
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
- void* queue[2];
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
- QUEUE_INIT(&ts_fn->queue);
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
- QUEUE* tmp;
127
+ struct uv__queue* tmp;
129
128
  struct data_queue_node* node;
130
- QUEUE_FOREACH(tmp, &func->queue) {
131
- node = QUEUE_DATA(tmp, struct data_queue_node, q);
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
- QUEUE_INIT(&func->queue);
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 (!QUEUE_EMPTY(&func->queue)) {
191
- QUEUE* q = QUEUE_HEAD(&func->queue);
192
- struct data_queue_node* node = QUEUE_DATA(q, struct data_queue_node, q);
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
- QUEUE_REMOVE(q);
197
- QUEUE_INIT(q);
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
- QUEUE* q = QUEUE_HEAD(&func->queue);
299
- struct data_queue_node* node = QUEUE_DATA(q, struct data_queue_node, q);
300
- QUEUE_REMOVE(q);
301
- QUEUE_INIT(q);
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
- QUEUE_INSERT_TAIL(&func->queue, &queue_node->q);
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(napi_env env, napi_threadsafe_function func) {
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(napi_env env, napi_threadsafe_function func) {
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
- typedef void *QUEUE[2];
22
-
23
- /* Private macros. */
24
- #define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
25
- #define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
26
- #define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
27
- #define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
28
-
29
- /* Public macros. */
30
- #define QUEUE_DATA(ptr, type, field) \
31
- ((type *) ((char *) (ptr) - offsetof(type, field)))
32
-
33
- /* Important note: mutating the list while QUEUE_FOREACH is
34
- * iterating over its elements results in undefined behavior.
35
- */
36
- #define QUEUE_FOREACH(q, h) \
37
- for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
38
-
39
- #define QUEUE_EMPTY(q) \
40
- ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
41
-
42
- #define QUEUE_HEAD(q) \
43
- (QUEUE_NEXT(q))
44
-
45
- #define QUEUE_INIT(q) \
46
- do { \
47
- QUEUE_NEXT(q) = (q); \
48
- QUEUE_PREV(q) = (q); \
49
- } \
50
- while (0)
51
-
52
- #define QUEUE_ADD(h, n) \
53
- do { \
54
- QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
55
- QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
56
- QUEUE_PREV(h) = QUEUE_PREV(n); \
57
- QUEUE_PREV_NEXT(h) = (h); \
58
- } \
59
- while (0)
60
-
61
- #define QUEUE_SPLIT(h, q, n) \
62
- do { \
63
- QUEUE_PREV(n) = QUEUE_PREV(h); \
64
- QUEUE_PREV_NEXT(n) = (n); \
65
- QUEUE_NEXT(n) = (q); \
66
- QUEUE_PREV(h) = QUEUE_PREV(q); \
67
- QUEUE_PREV_NEXT(h) = (h); \
68
- QUEUE_PREV(q) = (n); \
69
- } \
70
- while (0)
71
-
72
- #define QUEUE_MOVE(h, n) \
73
- do { \
74
- if (QUEUE_EMPTY(h)) \
75
- QUEUE_INIT(n); \
76
- else { \
77
- QUEUE* q = QUEUE_HEAD(h); \
78
- QUEUE_SPLIT(h, q, n); \
79
- } \
80
- } \
81
- while (0)
82
-
83
- #define QUEUE_INSERT_HEAD(h, q) \
84
- do { \
85
- QUEUE_NEXT(q) = QUEUE_NEXT(h); \
86
- QUEUE_PREV(q) = (h); \
87
- QUEUE_NEXT_PREV(q) = (q); \
88
- QUEUE_NEXT(h) = (q); \
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_ */