diff --git a/packages/emnapi/CMakeLists.txt b/packages/emnapi/CMakeLists.txt index debfa133..3bf390bd 100644 --- a/packages/emnapi/CMakeLists.txt +++ b/packages/emnapi/CMakeLists.txt @@ -33,6 +33,7 @@ set(UV_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/uv-common.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/threadpool.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/unix/loop.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/unix/posix-hrtime.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/unix/thread.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/unix/async.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/uv/unix/core.c" diff --git a/packages/emnapi/include/node/uv.h b/packages/emnapi/include/node/uv.h index 1d0bb637..2924adad 100644 --- a/packages/emnapi/include/node/uv.h +++ b/packages/emnapi/include/node/uv.h @@ -3,6 +3,12 @@ #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT) +/* Internal type, do not use. */ +struct uv__queue { + struct uv__queue* next; + struct uv__queue* prev; +}; + #include #include "uv/unix.h" @@ -29,6 +35,8 @@ typedef struct uv_work_s uv_work_t; typedef struct uv_handle_s uv_handle_t; typedef struct uv_async_s uv_async_t; +typedef struct uv_metrics_s uv_metrics_t; + typedef void (*uv_work_cb)(uv_work_t* req); typedef void (*uv_after_work_cb)(uv_work_t* req, int status); @@ -40,10 +48,22 @@ struct uv_req_s { UV_REQ_FIELDS }; +typedef void* (*uv_malloc_func)(size_t size); +typedef void* (*uv_realloc_func)(void* ptr, size_t size); +typedef void* (*uv_calloc_func)(size_t count, size_t size); +typedef void (*uv_free_func)(void* ptr); + UV_EXTERN void uv_library_shutdown(void); + +UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func, + uv_realloc_func realloc_func, + uv_calloc_func calloc_func, + uv_free_func free_func); + UV_EXTERN uv_loop_t* uv_default_loop(void); UV_EXTERN int uv_loop_init(uv_loop_t* loop); UV_EXTERN int uv_loop_close(uv_loop_t* loop); +UV_EXTERN uint64_t uv_hrtime(void); UV_EXTERN void uv_sleep(unsigned int msec); UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value); @@ -111,6 +131,12 @@ typedef void (*uv_async_cb)(uv_async_t* handle); uv_loop_t* loop; \ uv_handle_type type; \ uv_close_cb close_cb; \ + void* handle_queue[2]; \ + union { \ + int fd; \ + void* reserved[4]; \ + } u; \ + UV_HANDLE_PRIVATE_FIELDS \ struct uv_handle_s { UV_HANDLE_FIELDS @@ -129,15 +155,30 @@ UV_EXTERN int uv_async_init(uv_loop_t*, UV_EXTERN int uv_async_send(uv_async_t* async); UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); +UV_EXTERN int uv_is_closing(const uv_handle_t* handle); + +struct uv_metrics_s { + uint64_t loop_count; + uint64_t events; + uint64_t events_waiting; + /* private */ + uint64_t* reserved[13]; +}; + +UV_EXTERN int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics); +UV_EXTERN uint64_t uv_metrics_idle_time(uv_loop_t* loop); struct uv_loop_s { void* data; + unsigned int active_handles; + void* handle_queue[2]; union { void* unused; unsigned int count; } active_reqs; - void* wq[2]; + void* internal_fields; + void* wq[2]; uv_mutex_t wq_mutex; uv_async_t wq_async; void* async_handles[2]; diff --git a/packages/emnapi/include/node/uv/unix.h b/packages/emnapi/include/node/uv/unix.h index 357463a0..8e3a3dcc 100644 --- a/packages/emnapi/include/node/uv/unix.h +++ b/packages/emnapi/include/node/uv/unix.h @@ -18,4 +18,8 @@ typedef pthread_cond_t uv_cond_t; #endif +#define UV_HANDLE_PRIVATE_FIELDS \ + uv_handle_t* next_closing; \ + unsigned int flags; \ + #endif /* UV_UNIX_H */ diff --git a/packages/emnapi/src/uv/threadpool.c b/packages/emnapi/src/uv/threadpool.c index 8ead208f..9182a0da 100644 --- a/packages/emnapi/src/uv/threadpool.c +++ b/packages/emnapi/src/uv/threadpool.c @@ -361,12 +361,15 @@ void uv__work_done(uv_async_t* handle) { QUEUE* q; QUEUE wq; int err; + int nevents; loop = container_of(handle, uv_loop_t, wq_async); uv_mutex_lock(&loop->wq_mutex); QUEUE_MOVE(&loop->wq, &wq); uv_mutex_unlock(&loop->wq_mutex); + nevents = 0; + while (!QUEUE_EMPTY(&wq)) { q = QUEUE_HEAD(&wq); QUEUE_REMOVE(q); @@ -374,6 +377,20 @@ void uv__work_done(uv_async_t* handle) { w = container_of(q, struct uv__work, wq); err = (w->work == uv__cancelled) ? ECANCELED : 0; w->done(w, err); + nevents++; + } + + /* This check accomplishes 2 things: + * 1. Even if the queue was empty, the call to uv__work_done() should count + * as an event. Which will have been added by the event loop when + * calling this callback. + * 2. Prevents accidental wrap around in case nevents == 0 events == 0. + */ + if (nevents > 1) { + /* Subtract 1 to counter the call to uv__work_done(). */ + uv__metrics_inc_events(loop, nevents - 1); + if (uv__get_internal_fields(loop)->current_timeout == 0) + uv__metrics_inc_events_waiting(loop, nevents - 1); } } diff --git a/packages/emnapi/src/uv/unix/async.c b/packages/emnapi/src/uv/unix/async.c index 238404d3..10e343bd 100644 --- a/packages/emnapi/src/uv/unix/async.c +++ b/packages/emnapi/src/uv/unix/async.c @@ -24,9 +24,11 @@ #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT) +#include "uv.h" +#include "internal.h" + #include #include -#include "../uv-common.h" #include "emnapi_common.h" #if defined(__clang__) || \ @@ -43,19 +45,6 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { return __sync_val_compare_and_swap(ptr, oldval, newval); } -#ifndef EMNAPI_NEXTTICK_TYPE -#define EMNAPI_NEXTTICK_TYPE 0 -#endif -#if EMNAPI_NEXTTICK_TYPE == 0 -EMNAPI_INTERNAL_EXTERN void _emnapi_set_immediate(void (*callback)(void*), void* data); -#define NEXT_TICK(callback, data) _emnapi_set_immediate((callback), (data)) -#elif EMNAPI_NEXTTICK_TYPE == 1 -EMNAPI_INTERNAL_EXTERN void _emnapi_next_tick(void (*callback)(void*), void* data); -#define NEXT_TICK(callback, data) _emnapi_next_tick((callback), (data)) -#else -#error "Invalid EMNAPI_NEXTTICK_TYPE" -#endif - #if EMNAPI_USE_PROXYING #include #include @@ -89,11 +78,13 @@ void _emnapi_destroy_proxying_queue(uv_loop_t* loop) {} #endif int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { - handle->loop = loop; - handle->type = UV_ASYNC; + uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC); handle->async_cb = async_cb; handle->pending = 0; + handle->u.fd = 0; /* This will be used as a busy flag. */ + QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue); + uv__handle_start(handle); return 0; } @@ -216,7 +207,7 @@ int uv_async_send(uv_async_t* handle) { void uv__async_close(uv_async_t* handle) { uv__async_spin(handle); QUEUE_REMOVE(&handle->queue); - NEXT_TICK(((void (*)(void *))handle->close_cb), handle); + uv__handle_stop(handle); } #endif diff --git a/packages/emnapi/src/uv/unix/core.c b/packages/emnapi/src/uv/unix/core.c index b9436d13..e6920de1 100644 --- a/packages/emnapi/src/uv/unix/core.c +++ b/packages/emnapi/src/uv/unix/core.c @@ -1,10 +1,18 @@ #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT) +#include "uv.h" +#include "internal.h" #include #include -#include "../uv-common.h" + +uint64_t uv_hrtime(void) { + return uv__hrtime(UV_CLOCK_PRECISE); +} void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { + assert(!uv__is_closing(handle)); + + handle->flags |= UV_HANDLE_CLOSING; handle->close_cb = close_cb; switch (handle->type) { @@ -14,6 +22,33 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { default: assert(0); } + + uv__make_close_pending(handle); +} + +static void uv__finish_close(uv_handle_t* handle) { + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + + uv__handle_unref(handle); + QUEUE_REMOVE(&handle->handle_queue); + + if (handle->close_cb) { + handle->close_cb(handle); + } +} + +void uv__make_close_pending(uv_handle_t* handle) { + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + // handle->next_closing = handle->loop->closing_handles; + // handle->loop->closing_handles = handle; + NEXT_TICK(((void (*)(void *))uv__finish_close), handle); +} + +int uv_is_closing(const uv_handle_t* handle) { + return uv__is_closing(handle); } int nanosleep(const struct timespec *, struct timespec *); diff --git a/packages/emnapi/src/uv/unix/internal.h b/packages/emnapi/src/uv/unix/internal.h new file mode 100644 index 00000000..fc20c11c --- /dev/null +++ b/packages/emnapi/src/uv/unix/internal.h @@ -0,0 +1,54 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef UV_UNIX_INTERNAL_H_ +#define UV_UNIX_INTERNAL_H_ + +#include "../uv-common.h" +#include "emnapi_common.h" +#include + +#ifndef EMNAPI_NEXTTICK_TYPE +#define EMNAPI_NEXTTICK_TYPE 0 +#endif +#if EMNAPI_NEXTTICK_TYPE == 0 +EMNAPI_INTERNAL_EXTERN void _emnapi_set_immediate(void (*callback)(void*), void* data); +#define NEXT_TICK(callback, data) _emnapi_set_immediate((callback), (data)) +#elif EMNAPI_NEXTTICK_TYPE == 1 +EMNAPI_INTERNAL_EXTERN void _emnapi_next_tick(void (*callback)(void*), void* data); +#define NEXT_TICK(callback, data) _emnapi_next_tick((callback), (data)) +#else +#error "Invalid EMNAPI_NEXTTICK_TYPE" +#endif + +typedef enum { + UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */ + UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ +} uv_clocktype_t; + +uint64_t uv__hrtime(uv_clocktype_t type); + +#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT) +void uv__async_close(uv_async_t* handle); +void uv__make_close_pending(uv_handle_t* handle); +#endif + +#endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/packages/emnapi/src/uv/unix/loop.c b/packages/emnapi/src/uv/unix/loop.c index 89389de3..12cf9dbb 100644 --- a/packages/emnapi/src/uv/unix/loop.c +++ b/packages/emnapi/src/uv/unix/loop.c @@ -1,16 +1,38 @@ #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT) #include "../uv-common.h" +#include +#include int _emnapi_create_proxying_queue(uv_loop_t* loop); void _emnapi_destroy_proxying_queue(uv_loop_t* loop); int uv_loop_init(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; + void* saved_data; int err; + + saved_data = loop->data; + memset(loop, 0, sizeof(*loop)); + loop->data = saved_data; + + lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields)); + if (lfields == NULL) + return ENOMEM; + loop->internal_fields = lfields; + + err = uv_mutex_init(&lfields->loop_metrics.lock); + if (err) + goto fail_metrics_mutex_init; + memset(&lfields->loop_metrics.metrics, + 0, + sizeof(lfields->loop_metrics.metrics)); + QUEUE_INIT(&loop->wq); QUEUE_INIT(&loop->async_handles); + QUEUE_INIT(&loop->handle_queue); err = _emnapi_create_proxying_queue(loop); - if (err) return err; + if (err) goto fail_proxying_queue_init; err = uv_mutex_init(&loop->wq_mutex); if (err) goto fail_mutex_init; err = uv_async_init(loop, &loop->wq_async, uv__work_done); @@ -21,16 +43,30 @@ int uv_loop_init(uv_loop_t* loop) { uv_mutex_destroy(&loop->wq_mutex); fail_mutex_init: + +fail_proxying_queue_init: + +fail_metrics_mutex_init: + uv__free(lfields); + loop->internal_fields = NULL; + return err; } void uv__loop_close(uv_loop_t* loop) { + uv__loop_internal_fields_t* lfields; + uv_mutex_lock(&loop->wq_mutex); assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!"); assert(!uv__has_active_reqs(loop)); _emnapi_destroy_proxying_queue(loop); uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); + + lfields = uv__get_internal_fields(loop); + uv_mutex_destroy(&lfields->loop_metrics.lock); + uv__free(lfields); + loop->internal_fields = NULL; } #endif diff --git a/packages/emnapi/src/uv/unix/posix-hrtime.c b/packages/emnapi/src/uv/unix/posix-hrtime.c new file mode 100644 index 00000000..7b45c01a --- /dev/null +++ b/packages/emnapi/src/uv/unix/posix-hrtime.c @@ -0,0 +1,36 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include +#include + +uint64_t uv__hrtime(uv_clocktype_t type) { + struct timespec t; + + if (clock_gettime(CLOCK_MONOTONIC, &t)) + abort(); + + return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; +} diff --git a/packages/emnapi/src/uv/uv-common.c b/packages/emnapi/src/uv/uv-common.c index 5ec3d012..bb38392a 100644 --- a/packages/emnapi/src/uv/uv-common.c +++ b/packages/emnapi/src/uv/uv-common.c @@ -1,9 +1,101 @@ #if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT) #include +#include +#include #include #include "uv-common.h" +typedef struct { + uv_malloc_func local_malloc; + uv_realloc_func local_realloc; + uv_calloc_func local_calloc; + uv_free_func local_free; +} uv__allocator_t; + +static uv__allocator_t uv__allocator = { + malloc, + realloc, + calloc, + free, +}; + +char* uv__strdup(const char* s) { + size_t len = strlen(s) + 1; + char* m = uv__malloc(len); + if (m == NULL) + return NULL; + return memcpy(m, s, len); +} + +char* uv__strndup(const char* s, size_t n) { + char* m; + size_t len = strlen(s); + if (n < len) + len = n; + m = uv__malloc(len + 1); + if (m == NULL) + return NULL; + m[len] = '\0'; + return memcpy(m, s, len); +} + +void* uv__malloc(size_t size) { + if (size > 0) + return uv__allocator.local_malloc(size); + return NULL; +} + +void uv__free(void* ptr) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; + uv__allocator.local_free(ptr); + errno = saved_errno; +} + +void* uv__calloc(size_t count, size_t size) { + return uv__allocator.local_calloc(count, size); +} + +void* uv__realloc(void* ptr, size_t size) { + if (size > 0) + return uv__allocator.local_realloc(ptr, size); + uv__free(ptr); + return NULL; +} + +void* uv__reallocf(void* ptr, size_t size) { + void* newptr; + + newptr = uv__realloc(ptr, size); + if (newptr == NULL) + if (size > 0) + uv__free(ptr); + + return newptr; +} + +int uv_replace_allocator(uv_malloc_func malloc_func, + uv_realloc_func realloc_func, + uv_calloc_func calloc_func, + uv_free_func free_func) { + if (malloc_func == NULL || realloc_func == NULL || + calloc_func == NULL || free_func == NULL) { + return EINVAL; + } + + uv__allocator.local_malloc = malloc_func; + uv__allocator.local_realloc = realloc_func; + uv__allocator.local_calloc = calloc_func; + uv__allocator.local_free = free_func; + + return 0; +} + static uv_loop_t default_loop_struct; static uv_loop_t* default_loop_ptr; @@ -67,4 +159,28 @@ void uv_library_shutdown(void) { // #endif } +int uv_metrics_info(uv_loop_t* loop, uv_metrics_t* metrics) { + memcpy(metrics, + &uv__get_loop_metrics(loop)->metrics, + sizeof(*metrics)); + + return 0; +} + +uint64_t uv_metrics_idle_time(uv_loop_t* loop) { + uv__loop_metrics_t* loop_metrics; + uint64_t entry_time; + uint64_t idle_time; + + loop_metrics = uv__get_loop_metrics(loop); + uv_mutex_lock(&loop_metrics->lock); + idle_time = loop_metrics->provider_idle_time; + entry_time = loop_metrics->provider_entry_time; + uv_mutex_unlock(&loop_metrics->lock); + + if (entry_time > 0) + idle_time += uv_hrtime() - entry_time; + return idle_time; +} + #endif diff --git a/packages/emnapi/src/uv/uv-common.h b/packages/emnapi/src/uv/uv-common.h index 2b822f59..72b3ae56 100644 --- a/packages/emnapi/src/uv/uv-common.h +++ b/packages/emnapi/src/uv/uv-common.h @@ -27,6 +27,106 @@ #define container_of(ptr, type, member) \ ((type *) ((char *) (ptr) - offsetof(type, member))) +/* Handle flags. Some flags are specific to Windows or UNIX. */ +enum { + /* Used by all handles. */ + UV_HANDLE_CLOSING = 0x00000001, + UV_HANDLE_CLOSED = 0x00000002, + UV_HANDLE_ACTIVE = 0x00000004, + UV_HANDLE_REF = 0x00000008, + UV_HANDLE_INTERNAL = 0x00000010, + UV_HANDLE_ENDGAME_QUEUED = 0x00000020 +}; + +#define uv__has_active_reqs(loop) \ + ((loop)->active_reqs.count > 0) + +#define uv__req_register(loop, req) \ + do { \ + (loop)->active_reqs.count++; \ + } \ + while (0) + +#define uv__req_unregister(loop, req) \ + do { \ + assert(uv__has_active_reqs(loop)); \ + (loop)->active_reqs.count--; \ + } \ + while (0) + +#define uv__has_active_handles(loop) \ + ((loop)->active_handles > 0) + +#define uv__active_handle_add(h) \ + do { \ + (h)->loop->active_handles++; \ + } \ + while (0) + +#define uv__active_handle_rm(h) \ + do { \ + (h)->loop->active_handles--; \ + } \ + while (0) + +#define uv__is_active(h) \ + (((h)->flags & UV_HANDLE_ACTIVE) != 0) + +#define uv__is_closing(h) \ + (((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0) +#define uv__handle_start(h) \ + do { \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_stop(h) \ + do { \ + if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \ + (h)->flags &= ~UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__handle_ref(h) \ + do { \ + if (((h)->flags & UV_HANDLE_REF) != 0) break; \ + (h)->flags |= UV_HANDLE_REF; \ + if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ + } \ + while (0) + +#define uv__handle_unref(h) \ + do { \ + if (((h)->flags & UV_HANDLE_REF) == 0) break; \ + (h)->flags &= ~UV_HANDLE_REF; \ + if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ + } \ + while (0) + +#define uv__has_ref(h) \ + (((h)->flags & UV_HANDLE_REF) != 0) + +#if defined(_WIN32) +# define uv__handle_platform_init(h) ((h)->u.fd = -1) +#else +# define uv__handle_platform_init(h) ((h)->next_closing = NULL) +#endif + +#define uv__handle_init(loop_, h, type_) \ + do { \ + (h)->loop = (loop_); \ + (h)->type = (type_); \ + (h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \ + QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ + uv__handle_platform_init(h); \ + } \ + while (0) + #define UV_REQ_INIT(req, typ) \ do { \ (req)->type = (typ); \ @@ -56,6 +156,27 @@ } \ while (0) +#define uv__get_internal_fields(loop) \ + ((uv__loop_internal_fields_t*) loop->internal_fields) + +#define uv__get_loop_metrics(loop) \ + (&uv__get_internal_fields(loop)->loop_metrics) + +#define uv__metrics_inc_loop_count(loop) \ + do { \ + uv__get_loop_metrics(loop)->metrics.loop_count++; \ + } while (0) + +#define uv__metrics_inc_events(loop, e) \ + do { \ + uv__get_loop_metrics(loop)->metrics.events += (e); \ + } while (0) + +#define uv__metrics_inc_events_waiting(loop, e) \ + do { \ + uv__get_loop_metrics(loop)->metrics.events_waiting += (e); \ + } while (0) + #define uv__exchange_int_relaxed(p, v) \ atomic_exchange_explicit((_Atomic int*)(p), v, memory_order_relaxed) @@ -68,7 +189,30 @@ enum uv__work_kind { void uv__threadpool_cleanup(void); void uv__work_done(uv_async_t* handle); void uv__loop_close(uv_loop_t* loop); -void uv__async_close(uv_async_t* handle); + +void *uv__calloc(size_t count, size_t size); +char *uv__strdup(const char* s); +char *uv__strndup(const char* s, size_t n); +void* uv__malloc(size_t size); +void uv__free(void* ptr); +void* uv__realloc(void* ptr, size_t size); +void* uv__reallocf(void* ptr, size_t size); + +typedef struct uv__loop_metrics_s uv__loop_metrics_t; +typedef struct uv__loop_internal_fields_s uv__loop_internal_fields_t; + +struct uv__loop_metrics_s { + uv_metrics_t metrics; + uint64_t provider_entry_time; + uint64_t provider_idle_time; + uv_mutex_t lock; +}; + +struct uv__loop_internal_fields_s { + unsigned int flags; + uv__loop_metrics_t loop_metrics; + int current_timeout; +}; #endif