Skip to content

Commit

Permalink
update uv source
Browse files Browse the repository at this point in the history
  • Loading branch information
toyobayashi committed Jun 19, 2024
1 parent 421fb33 commit 69f82d8
Show file tree
Hide file tree
Showing 11 changed files with 496 additions and 21 deletions.
1 change: 1 addition & 0 deletions packages/emnapi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
43 changes: 42 additions & 1 deletion packages/emnapi/include/node/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <stddef.h>
#include "uv/unix.h"

Expand All @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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];
Expand Down
4 changes: 4 additions & 0 deletions packages/emnapi/include/node/uv/unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
17 changes: 17 additions & 0 deletions packages/emnapi/src/uv/threadpool.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,19 +361,36 @@ 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);

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);
}
}

Expand Down
25 changes: 8 additions & 17 deletions packages/emnapi/src/uv/unix/async.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@

#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)

#include "uv.h"
#include "internal.h"

#include <stdlib.h>
#include <sched.h>
#include "../uv-common.h"
#include "emnapi_common.h"

#if defined(__clang__) || \
Expand All @@ -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 <emscripten/threading.h>
#include <emscripten/proxying.h>
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
37 changes: 36 additions & 1 deletion packages/emnapi/src/uv/unix/core.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)

#include "uv.h"
#include "internal.h"
#include <errno.h>
#include <time.h>
#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) {
Expand All @@ -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 *);
Expand Down
54 changes: 54 additions & 0 deletions packages/emnapi/src/uv/unix/internal.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>

#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_ */
38 changes: 37 additions & 1 deletion packages/emnapi/src/uv/unix/loop.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
#if defined(__EMSCRIPTEN_PTHREADS__) || defined(_REENTRANT)

#include "../uv-common.h"
#include <errno.h>
#include <string.h>

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);
Expand All @@ -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
Loading

0 comments on commit 69f82d8

Please sign in to comment.