Browse Source

uv: upgrade to 87dbffbd

v0.9.1-release
Bert Belder 13 years ago
committed by Fedor Indutny
parent
commit
30a0e58d63
  1. 2
      deps/uv/include/uv-private/ev.h
  2. 45
      deps/uv/include/uv-private/uv-unix.h
  3. 2
      deps/uv/include/uv-private/uv-win.h
  4. 47
      deps/uv/include/uv.h
  5. 181
      deps/uv/src/unix/core.c
  6. 95
      deps/uv/src/unix/ev/ev.c
  7. 24
      deps/uv/src/unix/internal.h
  8. 5
      deps/uv/src/unix/loop.c
  9. 2
      deps/uv/src/unix/pipe.c
  10. 56
      deps/uv/src/unix/process.c
  11. 7
      deps/uv/src/unix/stream.c
  12. 120
      deps/uv/src/unix/timer.c
  13. 16
      deps/uv/src/unix/uv-eio.c
  14. 12
      deps/uv/src/uv-common.c
  15. 36
      deps/uv/src/uv-common.h
  16. 6
      deps/uv/src/win/async.c
  17. 1
      deps/uv/src/win/core.c
  18. 5
      deps/uv/src/win/fs-event.c
  19. 6
      deps/uv/src/win/handle.c
  20. 13
      deps/uv/src/win/internal.h
  21. 5
      deps/uv/src/win/loop-watcher.c
  22. 7
      deps/uv/src/win/pipe.c
  23. 20
      deps/uv/src/win/poll.c
  24. 551
      deps/uv/src/win/process.c
  25. 6
      deps/uv/src/win/tcp.c
  26. 6
      deps/uv/src/win/timer.c
  27. 6
      deps/uv/src/win/tty.c
  28. 6
      deps/uv/src/win/udp.c
  29. 2
      deps/uv/test/benchmark-list.h
  30. 36
      deps/uv/test/benchmark-loop-count.c
  31. 16
      deps/uv/test/run-tests.c
  32. 6
      deps/uv/test/test-list.h
  33. 19
      deps/uv/test/test-loop-handles.c
  34. 66
      deps/uv/test/test-spawn.c
  35. 77
      deps/uv/test/test-walk-handles.c
  36. 1
      deps/uv/uv.gyp

2
deps/uv/include/uv-private/ev.h

@ -623,7 +623,7 @@ enum {
};
#if EV_PROTOTYPES
void ev_run (EV_P_ int flags EV_CPP (= 0));
void ev_run (EV_P_ ev_tstamp waittime);
void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)); /* break out of the loop */
/*

45
deps/uv/include/uv-private/uv-unix.h

@ -98,18 +98,21 @@ struct uv__io_s {
# define UV_LOOP_PRIVATE_PLATFORM_FIELDS
#endif
#define UV_LOOP_PRIVATE_FIELDS \
/* Poll result queue */ \
eio_channel uv_eio_channel; \
struct ev_loop* ev; \
/* Various thing for libeio. */ \
uv_async_t uv_eio_want_poll_notifier; \
uv_async_t uv_eio_done_poll_notifier; \
uv_idle_t uv_eio_poller; \
uv_handle_t* pending_handles; \
ngx_queue_t prepare_handles; \
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
#define UV_LOOP_PRIVATE_FIELDS \
/* Poll result queue */ \
eio_channel uv_eio_channel; \
struct ev_loop* ev; \
/* Various thing for libeio. */ \
uv_async_t uv_eio_want_poll_notifier; \
uv_async_t uv_eio_done_poll_notifier; \
uv_idle_t uv_eio_poller; \
uv_handle_t* closing_handles; \
ngx_queue_t prepare_handles; \
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
/* RB_HEAD(uv__timers, uv_timer_s) */ \
struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles; \
uint64_t time; \
UV_LOOP_PRIVATE_PLATFORM_FIELDS
#define UV_REQ_BUFSML_SIZE (4)
@ -144,7 +147,7 @@ struct uv__io_s {
/* TODO: union or classes please! */
#define UV_HANDLE_PRIVATE_FIELDS \
int flags; \
uv_handle_t* next_pending; \
uv_handle_t* next_closing; \
#define UV_STREAM_PRIVATE_FIELDS \
@ -186,7 +189,7 @@ struct uv__io_s {
uv__io_t io_watcher;
/* UV_PREPARE */ \
/* UV_PREPARE */
#define UV_PREPARE_PRIVATE_FIELDS \
uv_prepare_cb prepare_cb; \
ngx_queue_t queue;
@ -211,9 +214,17 @@ struct uv__io_s {
/* UV_TIMER */
#define UV_TIMER_PRIVATE_FIELDS \
ev_timer timer_watcher; \
uv_timer_cb timer_cb;
#define UV_TIMER_PRIVATE_FIELDS \
/* RB_ENTRY(uv_timer_s) node; */ \
struct { \
struct uv_timer_s* rbe_left; \
struct uv_timer_s* rbe_right; \
struct uv_timer_s* rbe_parent; \
int rbe_color; \
} tree_entry; \
uv_timer_cb timer_cb; \
uint64_t timeout; \
uint64_t repeat;
#define UV_GETADDRINFO_PRIVATE_FIELDS \
uv_getaddrinfo_cb cb; \

2
deps/uv/include/uv-private/uv-win.h

@ -454,7 +454,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
struct uv_process_close_s { \
UV_REQ_FIELDS \
} close_req; \
HANDLE child_stdio[3]; \
void* child_stdio_buffer; \
int exit_signal; \
DWORD spawn_errno; \
HANDLE wait_handle; \

47
deps/uv/include/uv.h

@ -301,6 +301,7 @@ typedef void (*uv_exit_cb)(uv_process_t*, int exit_status, int term_signal);
typedef void (*uv_fs_cb)(uv_fs_t* req);
typedef void (*uv_work_cb)(uv_work_t* req);
typedef void (*uv_after_work_cb)(uv_work_t* req);
typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
/*
* This will be called repeatedly after the uv_fs_event_t is initialized.
@ -382,6 +383,7 @@ struct uv_shutdown_s {
/* read-only */ \
uv_handle_type type; \
/* private */ \
ngx_queue_t handle_queue; \
UV_HANDLE_PRIVATE_FIELDS \
/* The abstract base class of all handles. */
@ -407,6 +409,12 @@ UV_EXTERN size_t uv_req_size(uv_req_type type);
*/
UV_EXTERN int uv_is_active(const uv_handle_t* handle);
/*
* Walk the list of open handles.
*/
UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
/*
* Request handle to be closed. close_cb will be called asynchronously after
* this call. This MUST be called on each handle before memory is released.
@ -1157,15 +1165,17 @@ UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
/* uv_spawn() options */
typedef enum {
UV_IGNORE = 0x00,
UV_CREATE_PIPE = 0x01,
/*
* UV_READABLE_PIPE and UV_WRITABLE_PIPE flags are set from
* the child process perspective.
UV_IGNORE = 0x00,
UV_CREATE_PIPE = 0x01,
UV_INHERIT_FD = 0x02,
UV_INHERIT_STREAM = 0x04,
/* When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
* determine the direction of flow, from the child process' perspective. Both
* flags may be specified to create a duplex data stream.
*/
UV_READABLE_PIPE = 0x02,
UV_WRITABLE_PIPE = 0x04,
UV_RAW_FD = 0x08
UV_READABLE_PIPE = 0x10,
UV_WRITABLE_PIPE = 0x20
} uv_stdio_flags;
typedef struct uv_stdio_container_s {
@ -1211,10 +1221,16 @@ typedef struct uv_process_options_s {
uv_gid_t gid;
/*
* A container of stdio streams (stdin/stdout/stderr)
* The `stdio` field points to an array of uv_stdio_container_t structs that
* describe the file descriptors that will be made available to the child
* process. The convention is that stdio[0] points to stdin, fd 1 is used for
* stdout, and fd 2 is stderr.
*
* Note that on windows file descriptors greater than 2 are available to the
* child process only if the child processes uses the MSVCRT runtime.
*/
uv_stdio_container_t* stdio;
int stdio_count;
uv_stdio_container_t* stdio;
} uv_process_options_t;
/*
@ -1238,7 +1254,15 @@ enum uv_process_flags {
* converting the argument list into a command line string. This option is
* only meaningful on Windows systems. On unix it is silently ignored.
*/
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2)
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
/*
* Spawn the child process in a detached state - this will make it a process
* group leader, and will effectively enable the child to keep running after
* the parent exits. Note that the child process will still keep the
* parent's event loop alive unless the parent process calls uv_unref() on
* the child's process handle.
*/
UV_PROCESS_DETACHED = (1 << 3)
};
/*
@ -1668,6 +1692,7 @@ struct uv_loop_s {
uv_err_t last_err;
/* Loop reference counting */
unsigned int active_handles;
ngx_queue_t handle_queue;
ngx_queue_t active_reqs;
/* User data - use this for whatever. */
void* data;

181
deps/uv/src/unix/core.c

@ -59,8 +59,6 @@
static uv_loop_t default_loop_struct;
static uv_loop_t* default_loop_ptr;
static void uv__finish_close(uv_handle_t* handle);
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
handle->close_cb = close_cb;
@ -116,7 +114,72 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
}
handle->flags |= UV_CLOSING;
uv__make_pending(handle);
handle->next_closing = handle->loop->closing_handles;
handle->loop->closing_handles = handle;
}
static void uv__finish_close(uv_handle_t* handle) {
assert(!uv__is_active(handle));
assert(handle->flags & UV_CLOSING);
assert(!(handle->flags & UV_CLOSED));
handle->flags |= UV_CLOSED;
switch (handle->type) {
case UV_PREPARE:
case UV_CHECK:
case UV_IDLE:
case UV_ASYNC:
case UV_TIMER:
case UV_PROCESS:
break;
case UV_NAMED_PIPE:
case UV_TCP:
case UV_TTY:
assert(!uv__io_active(&((uv_stream_t*)handle)->read_watcher));
assert(!uv__io_active(&((uv_stream_t*)handle)->write_watcher));
assert(((uv_stream_t*)handle)->fd == -1);
uv__stream_destroy((uv_stream_t*)handle);
break;
case UV_UDP:
uv__udp_finish_close((uv_udp_t*)handle);
break;
case UV_FS_EVENT:
break;
case UV_POLL:
break;
default:
assert(0);
break;
}
uv__handle_unref(handle);
ngx_queue_remove(&handle->handle_queue);
if (handle->close_cb) {
handle->close_cb(handle);
}
}
static void uv__run_closing_handles(uv_loop_t* loop) {
uv_handle_t* p;
uv_handle_t* q;
p = loop->closing_handles;
loop->closing_handles = NULL;
while (p) {
q = p->next_closing;
uv__finish_close(p);
p = q;
}
}
@ -163,67 +226,44 @@ void uv_loop_delete(uv_loop_t* loop) {
}
static void uv__run_pending(uv_loop_t* loop) {
uv_handle_t* p;
uv_handle_t* q;
if (!loop->pending_handles)
return;
for (p = loop->pending_handles, loop->pending_handles = NULL; p; p = q) {
q = p->next_pending;
p->next_pending = NULL;
p->flags &= ~UV__PENDING;
if (p->flags & UV_CLOSING) {
uv__finish_close(p);
continue;
}
switch (p->type) {
case UV_NAMED_PIPE:
case UV_TCP:
case UV_TTY:
uv__stream_pending((uv_stream_t*)p);
break;
default:
abort();
}
}
}
static void uv__poll(uv_loop_t* loop, int block) {
static void uv__poll(uv_loop_t* loop, unsigned int timeout) {
/* bump the loop's refcount, otherwise libev does
* a zero timeout poll and we end up busy looping
*/
ev_ref(loop->ev);
ev_run(loop->ev, block ? EVRUN_ONCE : EVRUN_NOWAIT);
ev_run(loop->ev, timeout / 1000.);
ev_unref(loop->ev);
}
static int uv__should_block(uv_loop_t* loop) {
return loop->active_handles && ngx_queue_empty(&loop->idle_handles);
static unsigned int uv__poll_timeout(uv_loop_t* loop) {
if (!uv__has_active_handles(loop))
return 0;
if (!ngx_queue_empty(&loop->idle_handles))
return 0;
return uv__next_timeout(loop);
}
static int uv__run(uv_loop_t* loop) {
uv_update_time(loop);
uv__run_timers(loop);
uv__run_idle(loop);
uv__run_pending(loop);
if (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) {
uv__run_prepare(loop);
/* Need to poll even if there are no active handles left, otherwise
* uv_work_t reqs won't complete...
*/
uv__poll(loop, uv__should_block(loop));
uv__poll(loop, uv__poll_timeout(loop));
uv__run_check(loop);
}
return uv__has_pending_handles(loop)
|| uv__has_active_handles(loop)
|| uv__has_active_reqs(loop);
uv__run_closing_handles(loop);
return uv__has_active_handles(loop) || uv__has_active_reqs(loop);
}
@ -244,66 +284,19 @@ void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle,
handle->loop = loop;
handle->type = type;
handle->flags = UV__REF; /* ref the loop when active */
handle->next_pending = NULL;
}
void uv__finish_close(uv_handle_t* handle) {
assert(!uv__is_active(handle));
assert(handle->flags & UV_CLOSING);
assert(!(handle->flags & UV_CLOSED));
handle->flags |= UV_CLOSED;
switch (handle->type) {
case UV_PREPARE:
case UV_CHECK:
case UV_IDLE:
case UV_ASYNC:
case UV_TIMER:
case UV_PROCESS:
break;
case UV_NAMED_PIPE:
case UV_TCP:
case UV_TTY:
assert(!uv__io_active(&((uv_stream_t*)handle)->read_watcher));
assert(!uv__io_active(&((uv_stream_t*)handle)->write_watcher));
assert(((uv_stream_t*)handle)->fd == -1);
uv__stream_destroy((uv_stream_t*)handle);
break;
case UV_UDP:
uv__udp_finish_close((uv_udp_t*)handle);
break;
case UV_FS_EVENT:
break;
case UV_POLL:
break;
default:
assert(0);
break;
}
if (handle->close_cb) {
handle->close_cb(handle);
}
uv__handle_unref(handle);
handle->flags = UV__HANDLE_REF; /* ref the loop when active */
handle->next_closing = NULL;
ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue);
}
void uv_update_time(uv_loop_t* loop) {
ev_now_update(loop->ev);
loop->time = uv_hrtime() / 1000000;
}
int64_t uv_now(uv_loop_t* loop) {
return (int64_t)(ev_now(loop->ev) * 1000);
return loop->time;
}

95
deps/uv/src/unix/ev/ev.c

@ -2389,7 +2389,7 @@ time_update (EV_P_ ev_tstamp max_block)
}
void
ev_run (EV_P_ int flags)
ev_run (EV_P_ ev_tstamp waittime)
{
#if EV_FEATURE_API
++loop_depth;
@ -2426,15 +2426,6 @@ ev_run (EV_P_ int flags)
}
#endif
#if EV_PREPARE_ENABLE
/* queue prepare watchers (and execute them) */
if (expect_false (preparecnt))
{
queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
EV_INVOKE_PENDING;
}
#endif
if (expect_false (loop_done))
break;
@ -2445,90 +2436,16 @@ ev_run (EV_P_ int flags)
/* update fd-related kernel structures */
fd_reify (EV_A);
/* calculate blocking time */
{
ev_tstamp waittime = 0.;
ev_tstamp sleeptime = 0.;
/* remember old timestamp for io_blocktime calculation */
ev_tstamp prev_mn_now = mn_now;
/* update time to cancel out callback processing overhead */
time_update (EV_A_ 1e100);
if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt)))
{
waittime = MAX_BLOCKTIME;
if (timercnt)
{
ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge;
if (waittime > to) waittime = to;
}
#if EV_PERIODIC_ENABLE
if (periodiccnt)
{
ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge;
if (waittime > to) waittime = to;
}
#endif
/* don't let timeouts decrease the waittime below timeout_blocktime */
if (expect_false (waittime < timeout_blocktime))
waittime = timeout_blocktime;
/* extra check because io_blocktime is commonly 0 */
if (expect_false (io_blocktime))
{
sleeptime = io_blocktime - (mn_now - prev_mn_now);
if (sleeptime > waittime - backend_fudge)
sleeptime = waittime - backend_fudge;
if (expect_true (sleeptime > 0.))
{
ev_sleep (sleeptime);
waittime -= sleeptime;
}
}
}
#if EV_FEATURE_API
++loop_count;
#endif
assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
/* update ev_rt_now, do magic */
time_update (EV_A_ waittime + sleeptime);
}
/* queue pending timers and reschedule them */
timers_reify (EV_A); /* relative timers called last */
#if EV_PERIODIC_ENABLE
periodics_reify (EV_A); /* absolute timers called first */
#endif
#if EV_IDLE_ENABLE
/* queue idle watchers unless other events are pending */
idle_reify (EV_A);
#endif
#if EV_CHECK_ENABLE
/* queue check watchers, to be executed first */
if (expect_false (checkcnt))
queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
++loop_count;
#endif
assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
backend_poll (EV_A_ waittime);
assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
EV_INVOKE_PENDING;
}
while (expect_true (
activecnt
&& !loop_done
&& !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
));
while (0);
if (loop_done == EVBREAK_ONE)
loop_done = EVBREAK_CANCEL;

24
deps/uv/src/unix/internal.h

@ -93,23 +93,9 @@ enum {
UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
UV_TCP_NODELAY = 0x100, /* Disable Nagle. */
UV_TCP_KEEPALIVE = 0x200, /* Turn on keep-alive. */
UV_TIMER_REPEAT = 0x100,
UV__PENDING = 0x800
UV_TCP_KEEPALIVE = 0x200 /* Turn on keep-alive. */
};
inline static int uv__has_pending_handles(const uv_loop_t* loop) {
return loop->pending_handles != NULL;
}
inline static void uv__make_pending(uv_handle_t* h) {
if (h->flags & UV__PENDING) return;
h->next_pending = h->loop->pending_handles;
h->loop->pending_handles = h;
h->flags |= UV__PENDING;
}
#define uv__make_pending(h) uv__make_pending((uv_handle_t*)(h))
inline static void uv__req_init(uv_loop_t* loop,
uv_req_t* req,
uv_req_type type) {
@ -164,8 +150,9 @@ int uv__tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay);
/* pipe */
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
/* poll */
void uv__poll_close(uv_poll_t* handle);
/* timer */
void uv__run_timers(uv_loop_t* loop);
unsigned int uv__next_timeout(uv_loop_t* loop);
/* various */
void uv__async_close(uv_async_t* handle);
@ -173,6 +160,7 @@ void uv__check_close(uv_check_t* handle);
void uv__fs_event_close(uv_fs_event_t* handle);
void uv__idle_close(uv_idle_t* handle);
void uv__pipe_close(uv_pipe_t* handle);
void uv__poll_close(uv_poll_t* handle);
void uv__prepare_close(uv_prepare_t* handle);
void uv__process_close(uv_process_t* handle);
void uv__stream_close(uv_stream_t* handle);
@ -180,8 +168,6 @@ void uv__timer_close(uv_timer_t* handle);
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
void uv__stream_pending(uv_stream_t* handle);
#define UV__F_IPC (1 << 0)
#define UV__F_NONBLOCK (1 << 1)
int uv__make_socketpair(int fds[2], int flags);

5
deps/uv/src/unix/loop.c

@ -37,12 +37,15 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
memset(loop, 0, sizeof(*loop));
RB_INIT(&loop->ares_handles);
RB_INIT(&loop->timer_handles);
ngx_queue_init(&loop->active_reqs);
ngx_queue_init(&loop->idle_handles);
ngx_queue_init(&loop->check_handles);
ngx_queue_init(&loop->prepare_handles);
loop->pending_handles = NULL;
ngx_queue_init(&loop->handle_queue);
loop->closing_handles = NULL;
loop->channel = NULL;
loop->time = uv_hrtime() / 1000000;
loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags);
ev_set_userdata(loop->ev, loop);
eio_channel_init(&loop->uv_eio_channel, loop);

2
deps/uv/src/unix/pipe.c

@ -218,7 +218,7 @@ out:
ngx_queue_init(&req->queue);
/* Run callback on next tick. */
uv__make_pending(handle);
uv__io_feed(handle->loop, &handle->write_watcher, UV__IO_WRITE);
/* Mimic the Windows pipe implementation, always
* return 0 and let the callback handle errors.

56
deps/uv/src/unix/process.c

@ -140,33 +140,39 @@ int uv__make_pipe(int fds[2], int flags) {
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2],
int writable) {
if (container->flags == UV_IGNORE) {
return 0;
} else if (container->flags & UV_CREATE_PIPE) {
assert(container->data.stream != NULL);
int fd = -1;
switch (container->flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
UV_INHERIT_STREAM)) {
case UV_IGNORE:
return 0;
case UV_CREATE_PIPE:
assert(container->data.stream != NULL);
if (container->data.stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
return -1;
}
if (container->data.stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
return -1;
}
return uv__make_socketpair(fds, 0);
case UV_INHERIT_FD:
case UV_INHERIT_STREAM:
if (container->flags & UV_INHERIT_FD) {
fd = container->data.fd;
} else {
fd = container->data.stream->fd;
}
return uv__make_socketpair(fds, 0);
} else if (container->flags & UV_RAW_FD) {
if (container->data.fd == -1) {
errno = EINVAL;
return -1;
}
if (fd == -1) {
errno = EINVAL;
return -1;
}
if (writable) {
fds[1] = container->data.fd;
} else {
fds[0] = container->data.fd;
}
fds[writable ? 1 : 0] = fd;
return 0;
} else {
assert(0 && "Unexpected flags");
return -1;
return 0;
default:
assert(0 && "Unexpected flags");
return -1;
}
}
@ -240,6 +246,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID)));
@ -301,6 +308,9 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
if (pid == 0) {
/* Child */
if (options.flags & UV_PROCESS_DETACHED) {
setsid();
}
/* Dup fds */
for (i = 0; i < options.stdio_count; i++) {

7
deps/uv/src/unix/stream.c

@ -718,11 +718,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
}
void uv__stream_pending(uv_stream_t* handle) {
uv__stream_io(handle->loop, &handle->write_watcher, UV__IO_WRITE);
}
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, int events) {
uv_stream_t* stream;
@ -859,7 +854,7 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr,
uv__io_start(stream->loop, &stream->write_watcher);
if (stream->delayed_error)
uv__make_pending(stream);
uv__io_feed(stream->loop, &stream->write_watcher, UV__IO_WRITE);
return 0;
}

120
deps/uv/src/unix/timer.c

@ -22,92 +22,114 @@
#include "internal.h"
#include <assert.h>
static int uv__timer_repeating(const uv_timer_t* timer) {
return timer->flags & UV_TIMER_REPEAT;
static int uv__timer_cmp(const uv_timer_t* a, const uv_timer_t* b) {
if (a->timeout < b->timeout)
return -1;
if (a->timeout > b->timeout)
return 1;
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
}
static void uv__timer_cb(EV_P_ ev_timer* w, int revents) {
uv_timer_t* timer = container_of(w, uv_timer_t, timer_watcher);
if (!uv__is_active(timer))
return;
if (!uv__timer_repeating(timer))
uv__handle_stop(timer);
if (timer->timer_cb)
timer->timer_cb(timer, 0);
}
RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp)
int uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
uv__handle_init(loop, (uv_handle_t*)timer, UV_TIMER);
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
loop->counters.timer_init++;
ev_init(&timer->timer_watcher, uv__timer_cb);
uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
handle->timer_cb = NULL;
return 0;
}
int uv_timer_start(uv_timer_t* timer,
int uv_timer_start(uv_timer_t* handle,
uv_timer_cb cb,
int64_t timeout,
int64_t repeat) {
if (uv__is_active(timer))
uv_timer_stop(timer);
assert(timeout >= 0);
assert(repeat >= 0);
timer->timer_cb = cb;
if (uv__is_active(handle))
uv_timer_stop(handle);
if (repeat)
timer->flags |= UV_TIMER_REPEAT;
else
timer->flags &= ~UV_TIMER_REPEAT;
handle->timer_cb = cb;
handle->timeout = handle->loop->time + timeout;
handle->repeat = repeat;
ev_timer_set(&timer->timer_watcher, timeout / 1000.0, repeat / 1000.0);
ev_timer_start(timer->loop->ev, &timer->timer_watcher);
uv__handle_start(timer);
RB_INSERT(uv__timers, &handle->loop->timer_handles, handle);
uv__handle_start(handle);
return 0;
}
int uv_timer_stop(uv_timer_t* timer) {
timer->flags &= ~UV_TIMER_REPEAT;
ev_timer_stop(timer->loop->ev, &timer->timer_watcher);
uv__handle_stop(timer);
int uv_timer_stop(uv_timer_t* handle) {
if (!uv__is_active(handle))
return 0;
RB_REMOVE(uv__timers, &handle->loop->timer_handles, handle);
uv__handle_stop(handle);
return 0;
}
int uv_timer_again(uv_timer_t* timer) {
if (!uv__is_active(timer)) {
uv__set_artificial_error(timer->loop, UV_EINVAL);
return -1;
int uv_timer_again(uv_timer_t* handle) {
if (handle->timer_cb == NULL)
return uv__set_artificial_error(handle->loop, UV_EINVAL);
if (handle->repeat) {
uv_timer_stop(handle);
uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
}
assert(uv__timer_repeating(timer));
ev_timer_again(timer->loop->ev, &timer->timer_watcher);
return 0;
}
void uv_timer_set_repeat(uv_timer_t* timer, int64_t repeat) {
assert(timer->type == UV_TIMER);
timer->timer_watcher.repeat = repeat / 1000.0;
void uv_timer_set_repeat(uv_timer_t* handle, int64_t repeat) {
assert(repeat >= 0);
handle->repeat = repeat;
}
int64_t uv_timer_get_repeat(uv_timer_t* handle) {
return handle->repeat;
}
unsigned int uv__next_timeout(uv_loop_t* loop) {
uv_timer_t* handle;
if (repeat)
timer->flags |= UV_TIMER_REPEAT;
else
timer->flags &= ~UV_TIMER_REPEAT;
handle = RB_MIN(uv__timers, &loop->timer_handles);
if (handle == NULL)
return (unsigned int) -1; /* block indefinitely */
if (handle->timeout <= loop->time)
return 0;
return handle->timeout - loop->time;
}
int64_t uv_timer_get_repeat(uv_timer_t* timer) {
assert(timer->type == UV_TIMER);
return (int64_t)(1000 * timer->timer_watcher.repeat);
void uv__run_timers(uv_loop_t* loop) {
uv_timer_t* handle;
while ((handle = RB_MIN(uv__timers, &loop->timer_handles))) {
if (handle->timeout > loop->time)
break;
uv_timer_stop(handle);
uv_timer_again(handle);
handle->timer_cb(handle, 0);
}
}

16
deps/uv/src/unix/uv-eio.c

@ -22,6 +22,7 @@
#include "uv.h"
#include "eio.h"
#include "internal.h"
#include <assert.h>
#include <stdio.h>
@ -87,13 +88,18 @@ void uv_eio_init(uv_loop_t* loop) {
uv_idle_init(loop, &loop->uv_eio_poller);
uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll);
loop->uv_eio_poller.flags |= UV__HANDLE_INTERNAL;
loop->uv_eio_want_poll_notifier.data = loop;
uv_async_init(loop, &loop->uv_eio_want_poll_notifier,
uv_eio_want_poll_notifier_cb);
uv_async_init(loop, &loop->uv_eio_done_poll_notifier,
uv_eio_done_poll_notifier_cb);
uv_async_init(loop,
&loop->uv_eio_want_poll_notifier,
uv_eio_want_poll_notifier_cb);
loop->uv_eio_want_poll_notifier.flags |= UV__HANDLE_INTERNAL;
uv_async_init(loop,
&loop->uv_eio_done_poll_notifier,
uv_eio_done_poll_notifier_cb);
loop->uv_eio_done_poll_notifier.flags |= UV__HANDLE_INTERNAL;
uv_once(&uv__eio_init_once_guard, uv__eio_init);
}

12
deps/uv/src/uv-common.c

@ -317,6 +317,18 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
}
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
ngx_queue_t* q;
uv_handle_t* h;
ngx_queue_foreach(q, &loop->handle_queue) {
h = ngx_queue_data(q, uv_handle_t, handle_queue);
if (h->flags & UV__HANDLE_INTERNAL) continue;
walk_cb(h, arg);
}
}
void uv_ref(uv_handle_t* handle) {
uv__handle_ref(handle);
}

36
deps/uv/src/uv-common.h

@ -49,12 +49,14 @@
#ifndef _WIN32
enum {
UV__ACTIVE = 0x4000,
UV__REF = 0x8000
UV__HANDLE_INTERNAL = 0x8000,
UV__HANDLE_ACTIVE = 0x4000,
UV__HANDLE_REF = 0x2000
};
#else
# define UV__REF 0x00000020
# define UV__ACTIVE 0x00000040
# define UV__HANDLE_INTERNAL 0x80
# define UV__HANDLE_ACTIVE 0x40
# define UV__HANDLE_REF 0x20
#endif
extern const uv_err_t uv_ok_;
@ -117,35 +119,35 @@ UNUSED static void uv__active_handle_rm(uv_handle_t* h) {
#define uv__req_unregister(loop, req) uv__req_unregister((loop), (uv_req_t*)(req))
UNUSED static int uv__is_active(const uv_handle_t* h) {
return !!(h->flags & UV__ACTIVE);
return !!(h->flags & UV__HANDLE_ACTIVE);
}
#define uv__is_active(h) uv__is_active((const uv_handle_t*)(h))
UNUSED static void uv__handle_start(uv_handle_t* h) {
if (h->flags & UV__ACTIVE) return;
if (h->flags & UV__REF) uv__active_handle_add(h);
h->flags |= UV__ACTIVE;
if (h->flags & UV__HANDLE_ACTIVE) return;
if (h->flags & UV__HANDLE_REF) uv__active_handle_add(h);
h->flags |= UV__HANDLE_ACTIVE;
}
#define uv__handle_start(h) uv__handle_start((uv_handle_t*)(h))
UNUSED static void uv__handle_stop(uv_handle_t* h) {
if (!(h->flags & UV__ACTIVE)) return;
if (h->flags & UV__REF) uv__active_handle_rm(h);
h->flags &= ~UV__ACTIVE;
if (!(h->flags & UV__HANDLE_ACTIVE)) return;
if (h->flags & UV__HANDLE_REF) uv__active_handle_rm(h);
h->flags &= ~UV__HANDLE_ACTIVE;
}
#define uv__handle_stop(h) uv__handle_stop((uv_handle_t*)(h))
UNUSED static void uv__handle_ref(uv_handle_t* h) {
if (h->flags & UV__REF) return;
if (h->flags & UV__ACTIVE) uv__active_handle_add(h);
h->flags |= UV__REF;
if (h->flags & UV__HANDLE_REF) return;
if (h->flags & UV__HANDLE_ACTIVE) uv__active_handle_add(h);
h->flags |= UV__HANDLE_REF;
}
#define uv__handle_ref(h) uv__handle_ref((uv_handle_t*)(h))
UNUSED static void uv__handle_unref(uv_handle_t* h) {
if (!(h->flags & UV__REF)) return;
if (h->flags & UV__ACTIVE) uv__active_handle_rm(h);
h->flags &= ~UV__REF;
if (!(h->flags & UV__HANDLE_REF)) return;
if (h->flags & UV__HANDLE_ACTIVE) uv__active_handle_rm(h);
h->flags &= ~UV__HANDLE_REF;
}
#define uv__handle_unref(h) uv__handle_unref((uv_handle_t*)(h))

6
deps/uv/src/win/async.c

@ -58,12 +58,8 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
!handle->async_sent) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}
}

1
deps/uv/src/win/core.c

@ -66,6 +66,7 @@ static void uv_loop_init(uv_loop_t* loop) {
uv_update_time(loop);
ngx_queue_init(&loop->handle_queue);
ngx_queue_init(&loop->active_reqs);
loop->active_handles = 0;

5
deps/uv/src/win/fs-event.c

@ -479,7 +479,6 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
!handle->req_pending) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->buffer) {
@ -507,8 +506,6 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
handle->dirw = NULL;
}
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}
}

6
deps/uv/src/win/handle.c

@ -57,13 +57,15 @@ uv_handle_type uv_guess_handle(uv_file file) {
int uv_is_active(const uv_handle_t* handle) {
return (handle->flags & UV__ACTIVE) && !(handle->flags & UV_HANDLE_CLOSING);
return (handle->flags & UV__HANDLE_ACTIVE) &&
!(handle->flags & UV_HANDLE_CLOSING);
}
void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) {
handle->loop = loop;
handle->flags = UV__REF;
handle->flags = UV__HANDLE_REF;
ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue);
loop->counters.handle_init++;
}

13
deps/uv/src/win/internal.h

@ -40,9 +40,8 @@
#define UV_HANDLE_ENDGAME_QUEUED 0x00000004
#define UV_HANDLE_ACTIVE 0x00000010
/* Keep in sync with uv-common.h: */
#define UV__REF 0x00000020
#define UV__ACTIVE 0x00000040
/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
/* reserved: #define UV_HANDLE_INTERNAL 0x00000080 */
/* Used by streams and UDP handles. */
@ -131,6 +130,14 @@ void uv_process_endgames(uv_loop_t* loop);
uv__req_unregister((loop), (req)); \
} while (0)
#define uv__handle_close(handle) \
do { \
ngx_queue_remove(&(handle)->handle_queue); \
(handle)->flags |= UV_HANDLE_CLOSED; \
if ((handle)->close_cb) { \
(handle)->close_cb((uv_handle_t*)(handle)); \
} \
} while (0)
/*
* Handles

5
deps/uv/src/win/loop-watcher.c

@ -30,10 +30,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->close_cb) {
handle->close_cb(handle);
}
uv__handle_close(handle);
}
}

7
deps/uv/src/win/pipe.c

@ -164,7 +164,7 @@ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
int err;
char* ptr = (char*)handle;
while (TRUE) {
for (;;) {
uv_unique_pipe_name(ptr, name, nameSize);
pipeHandle = CreateNamedPipeA(name,
@ -358,7 +358,6 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->flags & UV_HANDLE_CONNECTION) {
@ -385,9 +384,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
handle->accept_reqs = NULL;
}
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}
}

20
deps/uv/src/win/poll.c

@ -94,7 +94,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
}
static int uv__fast_poll_cancel_poll_reqs(uv_loop_t* loop, uv_poll_t* handle) {
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO afd_poll_info;
DWORD result;
HANDLE event;
@ -106,15 +106,15 @@ static int uv__fast_poll_cancel_poll_reqs(uv_loop_t* loop, uv_poll_t* handle) {
return -1;
}
afd_poll_info.Exclusive = TRUE;
afd_poll_info.Exclusive = FALSE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Timeout.QuadPart = 0;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
memset(&overlapped, 0, sizeof overlapped);
overlapped.hEvent = (HANDLE) ((uintptr_t) event & 1);
overlapped.hEvent = (HANDLE) ((uintptr_t) event | 1);
result = uv_msafd_poll(handle->socket,
&afd_poll_info,
@ -129,6 +129,10 @@ static int uv__fast_poll_cancel_poll_reqs(uv_loop_t* loop, uv_poll_t* handle) {
}
}
if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
CloseHandle(event);
return 0;
}
@ -234,7 +238,7 @@ static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_2.overlapped);
} else if (handle->submitted_events_1 | handle->submitted_events_2) {
/* Execute another unique poll to force the others to return. */
uv__fast_poll_cancel_poll_reqs(loop, handle);
uv__fast_poll_cancel_poll_req(loop, handle);
}
}
}
@ -611,10 +615,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
assert(handle->submitted_events_1 == 0);
assert(handle->submitted_events_2 == 0);
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}

551
deps/uv/src/win/process.c

@ -22,15 +22,28 @@
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <io.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <signal.h>
#include <windows.h>
#define SIGKILL 9
/* CRT file descriptor mode flags */
#define FOPEN 0x01
#define FEOFLAG 0x02
#define FCRLF 0x04
#define FPIPE 0x08
#define FNOINHERIT 0x10
#define FAPPEND 0x20
#define FDEV 0x40
#define FTEXT 0x80
typedef struct env_var {
const char* narrow;
const wchar_t* wide;
@ -41,6 +54,7 @@ typedef struct env_var {
#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
#define UTF8_TO_UTF16(s, t) \
size = uv_utf8_to_utf16(s, NULL, 0) * sizeof(wchar_t); \
t = (wchar_t*)malloc(size); \
@ -54,6 +68,37 @@ typedef struct env_var {
}
/* The `child_stdio_buffer` buffer has the following layout:
* int number_of_fds
* unsigned char crt_flags[number_of_fds]
* HANDLE os_handle[number_of_fds]
*/
#define CHILD_STDIO_SIZE(count) \
(sizeof(int) + \
sizeof(unsigned char) * (count) + \
sizeof(uintptr_t) * (count))
#define CHILD_STDIO_COUNT(buffer) \
*((unsigned int*) (buffer))
#define CHILD_STDIO_LPRESERVED2(buffer) \
((LPBYTE) (buffer))
#define CHILD_STDIO_CBRESERVED2(buffer) \
CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)))
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
*((unsigned char*) (buffer) + sizeof(int) + fd)
#define CHILD_STDIO_HANDLE(buffer, fd) \
*((HANDLE*) ((unsigned char*) (buffer) + \
sizeof(int) + \
sizeof(unsigned char) * \
CHILD_STDIO_COUNT((buffer)) + \
sizeof(HANDLE) * (fd)))
static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
uv_handle_init(loop, (uv_handle_t*) handle);
handle->type = UV_PROCESS;
@ -63,9 +108,7 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
handle->wait_handle = INVALID_HANDLE_VALUE;
handle->process_handle = INVALID_HANDLE_VALUE;
handle->close_handle = INVALID_HANDLE_VALUE;
handle->child_stdio[0] = INVALID_HANDLE_VALUE;
handle->child_stdio[1] = INVALID_HANDLE_VALUE;
handle->child_stdio[2] = INVALID_HANDLE_VALUE;
handle->child_stdio_buffer = NULL;
uv_req_init(loop, (uv_req_t*)&handle->exit_req);
handle->exit_req.type = UV_PROCESS_EXIT;
@ -594,6 +637,153 @@ wchar_t* make_program_env(char** env_block) {
}
static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
HANDLE* child_pipe_ptr, unsigned int flags) {
char pipe_name[64];
SECURITY_ATTRIBUTES sa;
DWORD server_access = 0;
DWORD client_access = 0;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
if (flags & UV_READABLE_PIPE) {
server_access |= PIPE_ACCESS_OUTBOUND;
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
}
if (flags & UV_WRITABLE_PIPE) {
server_access |= PIPE_ACCESS_INBOUND;
client_access |= GENERIC_WRITE;
}
/* Create server pipe handle. */
if (uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name)) < 0) {
goto error;
}
/* Create child pipe handle. */
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
child_pipe = CreateFileA(pipe_name,
client_access,
0,
&sa,
OPEN_EXISTING,
server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (child_pipe == INVALID_HANDLE_VALUE) {
uv__set_sys_error(loop, GetLastError());
goto error;
}
#ifndef NDEBUG
/* Validate that the pipe was opened in the right mode. */
{
DWORD mode;
BOOL r = GetNamedPipeHandleState(child_pipe,
&mode,
NULL,
NULL,
NULL,
NULL,
0);
assert(r == TRUE);
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
}
#endif
/* Do a blocking ConnectNamedPipe. This should not block because we have */
/* both ends of the pipe created. */
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
uv__set_sys_error(loop, GetLastError());
goto error;
}
}
*child_pipe_ptr = child_pipe;
return 0;
error:
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
uv_pipe_cleanup(loop, server_pipe);
}
if (child_pipe != INVALID_HANDLE_VALUE) {
CloseHandle(child_pipe);
}
return -1;
}
static int duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
current_process = GetCurrentProcess();
if (!DuplicateHandle(current_process,
handle,
current_process,
dup,
0,
TRUE,
DUPLICATE_SAME_ACCESS)) {
*dup = INVALID_HANDLE_VALUE;
uv__set_sys_error(loop, GetLastError());
return -1;
}
return 0;
}
static int duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
HANDLE handle;
if (fd == -1) {
*dup = INVALID_HANDLE_VALUE;
uv__set_artificial_error(loop, UV_EBADF);
return -1;
}
handle = (HANDLE)_get_osfhandle(fd);
return duplicate_handle(loop, handle, dup);
}
static void set_child_stdio_noinherit(void* buffer) {
int i, count;
count = CHILD_STDIO_COUNT(buffer);
for (i = 0; i < count; i++) {
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
if (handle != INVALID_HANDLE_VALUE) {
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
}
}
}
static void close_and_free_child_stdio(void* buffer) {
int i, count;
count = CHILD_STDIO_COUNT(buffer);
for (i = 0; i < count; i++) {
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
}
}
free(buffer);
}
/*
* Called on Windows thread-pool thread to indicate that
* a child process has exited.
@ -636,7 +826,7 @@ static DWORD WINAPI spawn_failure(void* data) {
char unknown[] = "unknown error\n";
uv_process_t* process = (uv_process_t*) data;
uv_loop_t* loop = process->loop;
HANDLE child_stderr = process->child_stdio[2];
HANDLE child_stderr = CHILD_STDIO_HANDLE(process->child_stdio_buffer, 2);
char* buf = NULL;
DWORD count, written;
@ -670,20 +860,6 @@ static DWORD WINAPI spawn_failure(void* data) {
}
static void close_child_stdio(uv_process_t* process) {
int i;
HANDLE handle;
for (i = 0; i < ARRAY_SIZE(process->child_stdio); i++) {
handle = process->child_stdio[i];
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
process->child_stdio[i] = INVALID_HANDLE_VALUE;
}
}
}
/* Called on main thread after a child process has exited. */
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
DWORD exit_code;
@ -743,158 +919,199 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
/* Clean-up the process handle. */
CloseHandle(handle->process_handle);
/* Clean up the child stdio ends that may have been left open. */
close_child_stdio(handle);
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
if (handle->child_stdio_buffer != NULL) {
close_and_free_child_stdio(handle->child_stdio_buffer);
}
uv__handle_close(handle);
}
}
static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe,
HANDLE* child_pipe, DWORD server_access, DWORD child_access,
int overlapped) {
int err;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
char pipe_name[64];
DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
static int init_child_stdio(uv_loop_t* loop, uv_process_options_t* options,
void** buffer_ptr) {
void* buffer;
int count, i;
if (server_pipe->type != UV_NAMED_PIPE) {
uv__set_artificial_error(loop, UV_EINVAL);
err = -1;
goto done;
}
count = options->stdio_count;
/* Create server pipe handle. */
err = uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name));
if (err) {
goto done;
if (count < 0 || count > 255) {
/* Only support FDs 0-255 */
uv__set_artificial_error(loop, UV_ENOTSUP);
return -1;
} else if (count < 3) {
/* There should always be at least 3 stdio handles. */
count = 3;
}
/* Create child pipe handle. */
*child_pipe = CreateFileA(pipe_name,
child_access,
0,
&sa,
OPEN_EXISTING,
overlapped ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (*child_pipe == INVALID_HANDLE_VALUE) {
uv__set_sys_error(loop, GetLastError());
err = -1;
goto done;
/* Allocate the child stdio buffer */
buffer = malloc(CHILD_STDIO_SIZE(count));
if (buffer == NULL) {
uv__set_artificial_error(loop, UV_ENOMEM);
return -1;
}
if (!SetNamedPipeHandleState(*child_pipe, &mode, NULL, NULL)) {
uv__set_sys_error(loop, GetLastError());
err = -1;
goto done;
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
/* clean up on failure. */
CHILD_STDIO_COUNT(buffer) = count;
for (i = 0; i < count; i++) {
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
}
/* Do a blocking ConnectNamedPipe. This should not block because
* we have both ends of the pipe created.
*/
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
uv__set_sys_error(loop, GetLastError());
err = -1;
goto done;
}
}
for (i = 0; i < options->stdio_count; i++) {
uv_stdio_container_t fdopt = options->stdio[i];
err = 0;
switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
UV_INHERIT_STREAM)) {
case UV_IGNORE:
/* The child is not supposed to inherit this handle. It has already */
/* been initialized to INVALID_HANDLE_VALUE, so just keep it like */
/* that. */
continue;
done:
if (err) {
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
uv_pipe_cleanup(loop, server_pipe);
}
case UV_CREATE_PIPE: {
/* Create a pair of two connected pipe ends; one end is turned into */
/* an uv_pipe_t for use by the parent. The other one is given to */
/* the child. */
uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
HANDLE child_pipe;
/* Create a new, connected pipe pair. stdio[i].stream should point */
/* to an uninitialized, but not connected pipe handle. */
assert(fdopt.data.stream->type == UV_NAMED_PIPE);
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
if (uv_create_stdio_pipe_pair(loop,
parent_pipe,
&child_pipe,
fdopt.flags) < 0) {
goto error;
}
if (*child_pipe != INVALID_HANDLE_VALUE) {
CloseHandle(*child_pipe);
*child_pipe = INVALID_HANDLE_VALUE;
}
}
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
}
return err;
}
case UV_INHERIT_FD: {
/* Inherit a raw FD. */
HANDLE child_handle;
/* Make an inheritable duplicate of the handle. */
if (duplicate_fd(loop, fdopt.data.fd, &child_handle) < 0) {
goto error;
}
static int duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
/* Figure out what the type is. */
switch (GetFileType(child_handle)) {
case FILE_TYPE_DISK:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
break;
case FILE_TYPE_PIPE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
case FILE_TYPE_CHAR:
case FILE_TYPE_REMOTE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
break;
case FILE_TYPE_UNKNOWN:
if (GetLastError != 0) {
uv__set_sys_error(loop, GetLastError());
CloseHandle(child_handle);
goto error;
}
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
break;
default:
assert(0);
}
current_process = GetCurrentProcess();
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
break;
}
if (!DuplicateHandle(current_process,
handle,
current_process,
dup,
0,
TRUE,
DUPLICATE_SAME_ACCESS)) {
*dup = INVALID_HANDLE_VALUE;
uv__set_sys_error(loop, GetLastError());
return -1;
}
case UV_INHERIT_STREAM: {
/* Use an existing stream as the stdio handle for the child. */
HANDLE stream_handle, child_handle;
unsigned char crt_flags;
uv_stream_t* stream = fdopt.data.stream;
/* Leech the handle out of the stream. */
if (stream->type = UV_TTY) {
stream_handle = ((uv_tty_t*) stream)->handle;
crt_flags = FOPEN | FDEV;
} else if (stream->type == UV_NAMED_PIPE &&
stream->flags & UV_HANDLE_CONNECTED) {
stream_handle = ((uv_pipe_t*) stream)->handle;
crt_flags = FOPEN | FPIPE;
} else {
stream_handle = INVALID_HANDLE_VALUE;
crt_flags = 0;
}
return 0;
}
if (stream_handle == NULL ||
stream_handle == INVALID_HANDLE_VALUE) {
/* The handle is already closed, or not yet created, or the */
/* stream type is not supported. */
uv__set_artificial_error(loop, UV_ENOTSUP);
goto error;
}
/* Make an inheritable copy of the handle. */
if (duplicate_handle(loop,
stream_handle,
&child_handle) < 0) {
goto error;
}
static int duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
HANDLE handle;
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
}
if (fd == -1) {
*dup = INVALID_HANDLE_VALUE;
uv__set_artificial_error(loop, UV_EBADF);
return -1;
default:
assert(0);
}
}
handle = (HANDLE)_get_osfhandle(fd);
return duplicate_handle(loop, handle, dup);
*buffer_ptr = buffer;
return 0;
error:
close_and_free_child_stdio(buffer);
return -1;
}
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv_process_options_t options) {
int err = 0, keep_child_stdio_open = 0;
int size, err = 0, keep_child_stdio_open = 0;
wchar_t* path = NULL;
int size, i, overlapped;
DWORD server_access, child_access;
BOOL result;
wchar_t* application_path = NULL, *application = NULL, *arguments = NULL,
*env = NULL, *cwd = NULL;
HANDLE* child_stdio = process->child_stdio;
*env = NULL, *cwd = NULL;
STARTUPINFOW startup;
PROCESS_INFORMATION info;
uv_pipe_t* pipe;
DWORD process_flags;
if (options.flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
uv__set_artificial_error(loop, UV_ENOTSUP);
return -1;
}
/* Only support FDs 0-2 */
if (options.stdio_count > 3) {
uv__set_artificial_error(loop, UV_ENOTSUP);
return -1;
}
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
UV_PROCESS_DETACHED |
UV_PROCESS_SETGID |
UV_PROCESS_SETUID)));
@ -913,8 +1130,11 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
if (size) {
cwd = (wchar_t*)malloc(size);
if (!cwd) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
uv__set_artificial_error(loop, UV_ENOMEM);
err = -1;
goto done;
}
GetCurrentDirectoryW(size, cwd);
} else {
uv__set_sys_error(loop, GetLastError());
@ -942,60 +1162,10 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
application_path = application;
}
for (i = 0; i < options.stdio_count || i < 3; i++) {
if (i >= options.stdio_count ||
options.stdio[i].flags == UV_IGNORE) {
child_stdio[i] = INVALID_HANDLE_VALUE;
continue;
}
if (options.stdio[i].flags & UV_RAW_FD) {
err = duplicate_fd(loop, options.stdio[i].data.fd, &child_stdio[i]);
} else if (options.stdio[i].data.stream->type == UV_NAMED_PIPE) {
pipe = (uv_pipe_t*)options.stdio[i].data.stream;
if (options.stdio[i].flags & UV_CREATE_PIPE) {
server_access = 0;
child_access = 0;
if (pipe->ipc) {
server_access = PIPE_ACCESS_DUPLEX;
child_access = GENERIC_READ | FILE_WRITE_ATTRIBUTES | GENERIC_WRITE;
overlapped = 1;
} else {
overlapped = 0;
if (options.stdio[i].flags & UV_READABLE_PIPE) {
server_access |= PIPE_ACCESS_OUTBOUND;
child_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
}
if (options.stdio[i].flags & UV_WRITABLE_PIPE) {
server_access |= PIPE_ACCESS_INBOUND;
child_access |= GENERIC_WRITE;
}
}
err = uv_create_stdio_pipe_pair(
loop,
pipe,
&child_stdio[i],
server_access,
child_access,
overlapped);
} else {
err = duplicate_handle(loop, pipe->handle, &child_stdio[i]);
}
} else if(options.stdio[i].data.stream->type == UV_TTY) {
err = duplicate_handle(loop,
((uv_tty_t*)options.stdio[i].data.stream)->handle, &child_stdio[i]);
} else {
err = -1;
uv__set_artificial_error(loop, UV_ENOTSUP);
}
if (err) {
goto done;
}
if (init_child_stdio(loop, &options, &process->child_stdio_buffer) < 0) {
err = -1;
goto done;
}
startup.cb = sizeof(startup);
@ -1003,18 +1173,23 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
startup.lpDesktop = NULL;
startup.lpTitle = NULL;
startup.dwFlags = STARTF_USESTDHANDLES;
startup.cbReserved2 = 0;
startup.lpReserved2 = NULL;
startup.hStdInput = child_stdio[0];
startup.hStdOutput = child_stdio[1];
startup.hStdError = child_stdio[2];
startup.cbReserved2 = CHILD_STDIO_CBRESERVED2(process->child_stdio_buffer);
startup.lpReserved2 = CHILD_STDIO_LPRESERVED2(process->child_stdio_buffer);
startup.hStdInput = CHILD_STDIO_HANDLE(process->child_stdio_buffer, 0);
startup.hStdOutput = CHILD_STDIO_HANDLE(process->child_stdio_buffer, 1);
startup.hStdError = CHILD_STDIO_HANDLE(process->child_stdio_buffer, 2);
process_flags = CREATE_UNICODE_ENVIRONMENT;
if (options.flags & UV_PROCESS_DETACHED) {
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
}
if (CreateProcessW(application_path,
arguments,
NULL,
NULL,
1,
CREATE_UNICODE_ENVIRONMENT,
process_flags,
env,
cwd,
&startup,
@ -1062,19 +1237,19 @@ done:
free(env);
free(path);
/* Under normal circumstances we should close the stdio handles now - */
/* the child now has its own duplicates, or something went horribly wrong. */
/* Under normal circumstances we should close the stdio handles now - the */
/* the child now has its own duplicates, or something went horribly wrong */
/* The only exception is when CreateProcess has failed, then we actually */
/* need to keep the stdio handles to report the error asynchronously. */
if (!keep_child_stdio_open) {
close_child_stdio(process);
if (process->child_stdio_buffer == NULL) {
/* Something went wrong before child stdio was initialized. */
} else if (!keep_child_stdio_open) {
close_and_free_child_stdio(process->child_stdio_buffer);
process->child_stdio_buffer = NULL;
} else {
/* We're keeping the handles open, the thread pool is going to have */
/* it's way with them. But at least make them non-inheritable. */
int i;
for (i = 0; i < ARRAY_SIZE(process->child_stdio); i++) {
SetHandleInformation(child_stdio[i], HANDLE_FLAG_INHERIT, 0);
}
set_child_stdio_noinherit(process->child_stdio_buffer);
}
if (err == 0) {

6
deps/uv/src/win/tcp.c

@ -197,7 +197,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
@ -236,10 +235,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
}
}
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
loop->active_tcp_streams--;
}
}

6
deps/uv/src/win/timer.c

@ -126,12 +126,8 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}
}

6
deps/uv/src/win/tty.c

@ -1773,12 +1773,8 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
assert(handle->read_raw_wait == NULL);
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}
}

6
deps/uv/src/win/udp.c

@ -155,12 +155,8 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_stop(handle);
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
uv__handle_close(handle);
}
}

2
deps/uv/test/benchmark-list.h

@ -21,6 +21,7 @@
BENCHMARK_DECLARE (sizes)
BENCHMARK_DECLARE (loop_count)
BENCHMARK_DECLARE (loop_count_timed)
BENCHMARK_DECLARE (ping_pongs)
BENCHMARK_DECLARE (tcp_write_batch)
BENCHMARK_DECLARE (tcp4_pound_100)
@ -55,6 +56,7 @@ HELPER_DECLARE (dns_server)
TASK_LIST_START
BENCHMARK_ENTRY (sizes)
BENCHMARK_ENTRY (loop_count)
BENCHMARK_ENTRY (loop_count_timed)
BENCHMARK_ENTRY (ping_pongs)
BENCHMARK_HELPER (ping_pongs, tcp4_echo_server)

36
deps/uv/test/benchmark-loop-count.c

@ -25,12 +25,20 @@
#include <stdio.h>
#include <stdlib.h>
#define NUM_TICKS (2 * 1000 * 1000)
static unsigned long ticks;
static uv_idle_t idle_handle;
static uv_timer_t timer_handle;
static void idle_cb(uv_idle_t* handle, int status) {
if (++ticks == NUM_TICKS)
uv_idle_stop(handle);
}
static void idle2_cb(uv_idle_t* handle, int status) {
ticks++;
}
@ -43,13 +51,35 @@ static void timer_cb(uv_timer_t* handle, int status) {
BENCHMARK_IMPL(loop_count) {
uv_loop_t* loop = uv_default_loop();
uv_timer_init(loop, &timer_handle);
uv_timer_start(&timer_handle, timer_cb, 5000, 0);
uint64_t ns;
uv_idle_init(loop, &idle_handle);
uv_idle_start(&idle_handle, idle_cb);
ns = uv_hrtime();
uv_run(loop);
ns = uv_hrtime() - ns;
ASSERT(ticks == NUM_TICKS);
LOGF("loop_count: %d ticks in %.2fs (%.0f/s)\n",
NUM_TICKS,
ns / 1e9,
NUM_TICKS / (ns / 1e9));
return 0;
}
BENCHMARK_IMPL(loop_count_timed) {
uv_loop_t* loop = uv_default_loop();
uv_idle_init(loop, &idle_handle);
uv_idle_start(&idle_handle, idle2_cb);
uv_timer_init(loop, &timer_handle);
uv_timer_start(&timer_handle, timer_cb, 5000, 0);
uv_run(loop);
LOGF("loop_count: %lu ticks (%.0f ticks/s)\n", ticks, ticks / 5.0);

16
deps/uv/test/run-tests.c

@ -22,6 +22,10 @@
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
# include <io.h>
#endif
#include "uv.h"
#include "runner.h"
#include "task.h"
@ -104,5 +108,17 @@ static int maybe_run_test(int argc, char **argv) {
while (1) uv_sleep(10000);
}
if (strcmp(argv[1], "spawn_helper5") == 0) {
const char* out = "fourth stdio!\n\0";
#ifdef _WIN32
DWORD bytes;
WriteFile((HANDLE) _get_osfhandle(3), out, strlen(out), &bytes, NULL);
#else
write(3, out, strlen(out));
fsync(3);
#endif
return 1;
}
return run_test(argv[1], TEST_TIMEOUT, 0);
}

6
deps/uv/test/test-list.h

@ -81,6 +81,7 @@ TEST_DECLARE (timer_start_twice)
TEST_DECLARE (idle_starvation)
TEST_DECLARE (loop_handles)
TEST_DECLARE (get_loadavg)
TEST_DECLARE (walk_handles)
TEST_DECLARE (ref)
TEST_DECLARE (idle_ref)
TEST_DECLARE (async_ref)
@ -118,7 +119,9 @@ TEST_DECLARE (pass_always)
TEST_DECLARE (spawn_exit_code)
TEST_DECLARE (spawn_stdout)
TEST_DECLARE (spawn_stdin)
TEST_DECLARE (spawn_stdio_greater_than_3)
TEST_DECLARE (spawn_and_kill)
TEST_DECLARE (spawn_detached)
TEST_DECLARE (spawn_and_kill_with_std)
TEST_DECLARE (spawn_and_ping)
TEST_DECLARE (spawn_setuid_fails)
@ -300,6 +303,7 @@ TASK_LIST_START
TEST_ENTRY (process_ref)
TEST_ENTRY (loop_handles)
TEST_ENTRY (walk_handles)
TEST_ENTRY (async)
@ -330,7 +334,9 @@ TASK_LIST_START
TEST_ENTRY (spawn_exit_code)
TEST_ENTRY (spawn_stdout)
TEST_ENTRY (spawn_stdin)
TEST_ENTRY (spawn_stdio_greater_than_3)
TEST_ENTRY (spawn_and_kill)
TEST_ENTRY (spawn_detached)
TEST_ENTRY (spawn_and_kill_with_std)
TEST_ENTRY (spawn_and_ping)
TEST_ENTRY (spawn_setuid_fails)

19
deps/uv/test/test-loop-handles.c

@ -148,7 +148,7 @@ static void idle_1_cb(uv_idle_t* handle, int status) {
ASSERT(idles_1_active > 0);
/* Init idle_2 and make it active */
if (!idle_2_is_active) {
if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) {
r = uv_idle_init(uv_default_loop(), &idle_2_handle);
ASSERT(r == 0);
r = uv_idle_start(&idle_2_handle, idle_2_cb);
@ -208,11 +208,6 @@ static void check_cb(uv_check_t* handle, int status) {
ASSERT(handle == &check_handle);
ASSERT(status == 0);
/* XXX
ASSERT(idles_1_active == 0);
ASSERT(idle_2_is_active == 0);
*/
if (loop_iteration < ITERATIONS) {
/* Make some idle watchers active */
for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) {
@ -250,9 +245,6 @@ static void prepare_2_cb(uv_prepare_t* handle, int status) {
ASSERT(handle == &prepare_2_handle);
ASSERT(status == 0);
/* XXX ASSERT(idles_1_active == 0); */
/* XXX ASSERT(idle_2_is_active == 0); */
/* prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), */
/* and it stops itself immediately. A started watcher is not queued */
/* until the next round, so when this callback is made */
@ -274,11 +266,6 @@ static void prepare_1_cb(uv_prepare_t* handle, int status) {
ASSERT(handle == &prepare_1_handle);
ASSERT(status == 0);
/* XXX
ASSERT(idles_1_active == 0);
ASSERT(idle_2_is_active == 0);
*/
if (loop_iteration % 2 == 0) {
r = uv_prepare_start(&prepare_2_handle, prepare_2_cb);
ASSERT(r == 0);
@ -340,12 +327,8 @@ TEST_IMPL(loop_handles) {
ASSERT(check_close_cb_called == 1);
/* idle_1_cb should be called a lot */
/* XXX ASSERT(idle_1_cb_called >= ITERATIONS * IDLE_COUNT * 2); */
ASSERT(idle_1_close_cb_called == IDLE_COUNT);
/* XXX ASSERT(idles_1_active == 0); */
/* XXX ASSERT(idle_2_cb_started >= ITERATIONS); */
/* XXX ASSERT(idle_2_cb_called == idle_2_cb_started); */
ASSERT(idle_2_close_cb_called == idle_2_cb_started);
ASSERT(idle_2_is_active == 0);

66
deps/uv/test/test-spawn.c

@ -99,6 +99,10 @@ static void kill_cb(uv_process_t* process, int exit_status, int term_signal) {
ASSERT(err.code == UV_ESRCH);
}
static void detach_failure_cb(uv_process_t* process, int exit_status, int term_signal) {
printf("detach_cb\n");
exit_cb_called++;
}
static uv_buf_t on_alloc(uv_handle_t* handle, size_t suggested_size) {
uv_buf_t buf;
@ -217,7 +221,7 @@ TEST_IMPL(spawn_stdout_to_file) {
options.stdio = stdio;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_RAW_FD;
options.stdio[1].flags = UV_INHERIT_FD;
options.stdio[1].data.fd = file;
options.stdio_count = 2;
@ -291,6 +295,40 @@ TEST_IMPL(spawn_stdin) {
}
TEST_IMPL(spawn_stdio_greater_than_3) {
int r;
uv_pipe_t pipe;
uv_stdio_container_t stdio[4];
init_process_options("spawn_helper5", exit_cb);
uv_pipe_init(uv_default_loop(), &pipe, 0);
options.stdio = stdio;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_IGNORE;
options.stdio[2].flags = UV_IGNORE;
options.stdio[3].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[3].data.stream = (uv_stream_t*)&pipe;
options.stdio_count = 4;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*) &pipe, on_alloc, on_read);
ASSERT(r == 0);
r = uv_run(uv_default_loop());
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
printf("output from stdio[3] is: %s", output);
ASSERT(strcmp("fourth stdio!\n", output) == 0);
return 0;
}
TEST_IMPL(spawn_and_kill) {
int r;
@ -314,6 +352,32 @@ TEST_IMPL(spawn_and_kill) {
return 0;
}
TEST_IMPL(spawn_detached) {
int r;
uv_err_t err;
init_process_options("spawn_helper4", detach_failure_cb);
options.flags |= UV_PROCESS_DETACHED;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
uv_unref((uv_handle_t*)&process);
r = uv_run(uv_default_loop());
ASSERT(r == 0);
ASSERT(exit_cb_called == 0);
err = uv_kill(process.pid, 0);
ASSERT(err.code == 0);
err = uv_kill(process.pid, 15);
ASSERT(err.code == 0);
return 0;
}
TEST_IMPL(spawn_and_kill_with_std) {
int r;

77
deps/uv/test/test-walk-handles.c

@ -0,0 +1,77 @@
/* 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.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <stdlib.h>
static char magic_cookie[] = "magic cookie";
static int seen_timer_handle;
static uv_timer_t timer;
static void walk_cb(uv_handle_t* handle, void* arg) {
ASSERT(arg == (void*)magic_cookie);
if (handle == (uv_handle_t*)&timer) {
seen_timer_handle++;
} else {
ASSERT(0 && "unexpected handle");
}
}
static void timer_cb(uv_timer_t* handle, int status) {
ASSERT(handle == &timer);
ASSERT(status == 0);
uv_walk(handle->loop, walk_cb, magic_cookie);
uv_close((uv_handle_t*)handle, NULL);
}
TEST_IMPL(walk_handles) {
uv_loop_t* loop;
int r;
loop = uv_default_loop();
r = uv_timer_init(loop, &timer);
ASSERT(r == 0);
r = uv_timer_start(&timer, timer_cb, 1, 0);
ASSERT(r == 0);
/* Start event loop, expect to see the timer handle in walk_cb. */
ASSERT(seen_timer_handle == 0);
r = uv_run(loop);
ASSERT(r == 0);
ASSERT(seen_timer_handle == 1);
/* Loop is finished, walk_cb should not see our timer handle. */
seen_timer_handle = 0;
uv_walk(loop, walk_cb, magic_cookie);
ASSERT(seen_timer_handle == 0);
return 0;
}

1
deps/uv/uv.gyp

@ -319,6 +319,7 @@
'test/test-ipc-send-recv.c',
'test/test-list.h',
'test/test-loop-handles.c',
'test/test-walk-handles.c',
'test/test-multiple-listen.c',
'test/test-pass-always.c',
'test/test-ping-pong.c',

Loading…
Cancel
Save