Browse Source

deps: upgrade libuv to 7556590

v0.9.1-release
Fedor Indutny 13 years ago
parent
commit
761e0c460a
  1. 55
      deps/uv/include/uv.h
  2. 3
      deps/uv/src/unix/core.c
  3. 6
      deps/uv/src/unix/internal.h
  4. 6
      deps/uv/src/unix/loop.c
  5. 204
      deps/uv/src/unix/process.c
  6. 8
      deps/uv/src/unix/sunos.c
  7. 32
      deps/uv/src/uv-common.h
  8. 21
      deps/uv/src/win/core.c
  9. 192
      deps/uv/src/win/process.c
  10. 8
      deps/uv/test/benchmark-spawn.c
  11. 5
      deps/uv/test/runner-win.c
  12. 10
      deps/uv/test/test-ipc.c
  13. 2
      deps/uv/test/test-list.h
  14. 101
      deps/uv/test/test-spawn.c
  15. 11
      deps/uv/test/test-stdio-over-pipes.c
  16. 24
      src/process_wrap.cc

55
deps/uv/include/uv.h

@ -334,17 +334,12 @@ UV_EXTERN uv_err_t uv_last_error(uv_loop_t*);
UV_EXTERN const char* uv_strerror(uv_err_t err);
UV_EXTERN const char* uv_err_name(uv_err_t err);
#ifndef UV_LEAN_AND_MEAN
# define UV_REQ_EXTRA_FIELDS ngx_queue_t active_queue;
#else
# define UV_REQ_EXTRA_FIELDS
#endif
#define UV_REQ_FIELDS \
/* public */ \
void* data; \
UV_REQ_EXTRA_FIELDS \
/* private */ \
ngx_queue_t active_queue; \
UV_REQ_PRIVATE_FIELDS \
/* read-only */ \
uv_req_type type; \
@ -378,12 +373,6 @@ struct uv_shutdown_s {
};
#ifndef UV_LEAN_AND_MEAN
# define UV_HANDLE_EXTRA_FIELDS ngx_queue_t active_queue;
#else
# define UV_HANDLE_EXTRA_FIELDS
#endif
#define UV_HANDLE_FIELDS \
/* read-only */ \
uv_loop_t* loop; \
@ -394,7 +383,6 @@ struct uv_shutdown_s {
uv_handle_type type; \
/* private */ \
UV_HANDLE_PRIVATE_FIELDS \
UV_HANDLE_EXTRA_FIELDS \
/* The abstract base class of all handles. */
struct uv_handle_s {
@ -1168,6 +1156,27 @@ UV_EXTERN int uv_getaddrinfo(uv_loop_t*, uv_getaddrinfo_t* handle,
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_READABLE_PIPE = 0x02,
UV_WRITABLE_PIPE = 0x04,
UV_RAW_FD = 0x08
} uv_stdio_flags;
typedef struct uv_stdio_container_s {
uv_stdio_flags flags;
union {
uv_stream_t* stream;
int fd;
} data;
} uv_stdio_container_t;
typedef struct uv_process_options_s {
uv_exit_cb exit_cb; /* Called after the process exits. */
const char* file; /* Path to program to execute. */
@ -1200,14 +1209,12 @@ typedef struct uv_process_options_s {
*/
uv_uid_t uid;
uv_gid_t gid;
/*
* The user should supply pointers to initialized uv_pipe_t structs for
* stdio. This is used to to send or receive input from the subprocess.
* The user is responsible for calling uv_close on them.
* A container of stdio streams (stdin/stdout/stderr)
*/
uv_pipe_t* stdin_stream;
uv_pipe_t* stdout_stream;
uv_pipe_t* stderr_stream;
uv_stdio_container_t* stdio;
int stdio_count;
} uv_process_options_t;
/*
@ -1659,15 +1666,11 @@ struct uv_loop_s {
uv_counters_t counters;
/* The last error */
uv_err_t last_err;
/* Loop reference counting */
unsigned int active_handles;
ngx_queue_t active_reqs;
/* User data - use this for whatever. */
void* data;
#ifndef UV_LEAN_AND_MEAN
ngx_queue_t active_reqs;
ngx_queue_t active_handles;
#else
unsigned int active_reqs;
unsigned int active_handles;
#endif
};

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

@ -204,8 +204,7 @@ static void uv__poll(uv_loop_t* loop, int block) {
static int uv__should_block(uv_loop_t* loop) {
return ngx_queue_empty(&loop->idle_handles)
&& !ngx_queue_empty(&loop->active_handles);
return loop->active_handles && ngx_queue_empty(&loop->idle_handles);
}

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

@ -115,11 +115,7 @@ inline static void uv__req_init(uv_loop_t* loop,
uv_req_type type) {
loop->counters.req_init++;
req->type = type;
#ifndef UV_LEAN_AND_MEAN
ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue);
#else
loop->active_reqs++;
#endif
uv__req_register(loop, req);
}
#define uv__req_init(loop, req, type) \
uv__req_init((loop), (uv_req_t*)(req), (type))

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

@ -36,12 +36,8 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
memset(loop, 0, sizeof(*loop));
#ifndef UV_LEAN_AND_MEAN
ngx_queue_init(&loop->active_handles);
ngx_queue_init(&loop->active_reqs);
#endif
RB_INIT(&loop->ares_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);

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

@ -138,19 +138,79 @@ int uv__make_pipe(int fds[2], int flags) {
* Used for initializing stdio streams like options.stdin_stream. Returns
* zero on success.
*/
static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2], int flags) {
if (handle->type != UV_NAMED_PIPE) {
errno = EINVAL;
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);
if (container->data.stream->type != UV_NAMED_PIPE) {
errno = EINVAL;
return -1;
}
return uv__make_socketpair(fds, 0);
} else if (container->flags & UV_RAW_FD) {
if (container->data.fd == -1) {
errno = EINVAL;
return -1;
}
if (writable) {
fds[1] = container->data.fd;
} else {
fds[0] = container->data.fd;
}
return 0;
} else {
assert(0 && "Unexpected flags");
return -1;
}
}
if (handle->ipc)
return uv__make_socketpair(fds, flags);
else
return uv__make_pipe(fds, flags);
static int uv__process_stdio_flags(uv_stdio_container_t* container,
int writable) {
if (container->data.stream->type == UV_NAMED_PIPE &&
((uv_pipe_t*)container->data.stream)->ipc) {
return UV_STREAM_READABLE | UV_STREAM_WRITABLE;
} else if (writable) {
return UV_STREAM_WRITABLE;
} else {
return UV_STREAM_READABLE;
}
}
static int uv__process_open_stream(uv_stdio_container_t* container, int fds[2],
int writable) {
int fd = fds[writable ? 1 : 0];
int child_fd = fds[writable ? 0 : 1];
int flags;
/* No need to create stream */
if (!(container->flags & UV_CREATE_PIPE) || fd < 0) {
return 0;
}
assert(child_fd >= 0);
close(child_fd);
uv__nonblock(fd, 1);
flags = uv__process_stdio_flags(container, writable);
return uv__stream_open((uv_stream_t*)container->data.stream, fd, flags);
}
static void uv__process_close_stream(uv_stdio_container_t* container) {
if (!(container->flags & UV_CREATE_PIPE)) return;
uv__stream_close((uv_stream_t*)container->data.stream);
}
#ifndef SPAWN_WAIT_EXEC
# define SPAWN_WAIT_EXEC 1
#endif
@ -162,16 +222,21 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
* by the child process.
*/
char** save_our_env = environ;
int stdin_pipe[2] = { -1, -1 };
int stdout_pipe[2] = { -1, -1 };
int stderr_pipe[2] = { -1, -1 };
int* pipes = malloc(2 * options.stdio_count * sizeof(int));
#if SPAWN_WAIT_EXEC
int signal_pipe[2] = { -1, -1 };
struct pollfd pfd;
#endif
int status;
pid_t pid;
int flags;
int i;
if (pipes == NULL) {
errno = ENOMEM;
goto error;
}
assert(options.file != NULL);
assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS |
@ -185,19 +250,17 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
process->exit_cb = options.exit_cb;
if (options.stdin_stream &&
uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) {
goto error;
}
if (options.stdout_stream &&
uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) {
goto error;
/* Init pipe pairs */
for (i = 0; i < options.stdio_count; i++) {
pipes[i * 2] = -1;
pipes[i * 2 + 1] = -1;
}
if (options.stderr_stream &&
uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) {
goto error;
/* Create socketpairs/pipes, or use raw fd */
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_init_stdio(&options.stdio[i], pipes + i * 2, i != 0)) {
goto error;
}
}
/* This pipe is used by the parent to wait until
@ -237,31 +300,25 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
}
if (pid == 0) {
if (stdin_pipe[0] >= 0) {
close(stdin_pipe[1]);
dup2(stdin_pipe[0], STDIN_FILENO);
} else {
/* Reset flags that might be set by Node */
uv__cloexec(STDIN_FILENO, 0);
uv__nonblock(STDIN_FILENO, 0);
}
if (stdout_pipe[1] >= 0) {
close(stdout_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
} else {
/* Reset flags that might be set by Node */
uv__cloexec(STDOUT_FILENO, 0);
uv__nonblock(STDOUT_FILENO, 0);
}
if (stderr_pipe[1] >= 0) {
close(stderr_pipe[0]);
dup2(stderr_pipe[1], STDERR_FILENO);
} else {
/* Reset flags that might be set by Node */
uv__cloexec(STDERR_FILENO, 0);
uv__nonblock(STDERR_FILENO, 0);
/* Child */
/* Dup fds */
for (i = 0; i < options.stdio_count; i++) {
/*
* stdin has swapped ends of pipe
* (it's the only one readable stream)
*/
int close_fd = i == 0 ? pipes[i * 2 + 1] : pipes[i * 2];
int use_fd = i == 0 ? pipes[i * 2] : pipes[i * 2 + 1];
if (use_fd >= 0) {
close(close_fd);
dup2(use_fd, i);
} else {
/* Reset flags that might be set by Node */
uv__cloexec(i, 0);
uv__nonblock(i, 0);
}
}
if (options.cwd && chdir(options.cwd)) {
@ -313,49 +370,32 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
ev_child_start(process->loop->ev, &process->child_watcher);
process->child_watcher.data = process;
if (stdin_pipe[1] >= 0) {
assert(options.stdin_stream);
assert(stdin_pipe[0] >= 0);
close(stdin_pipe[0]);
uv__nonblock(stdin_pipe[1], 1);
flags = UV_STREAM_WRITABLE |
(options.stdin_stream->ipc ? UV_STREAM_READABLE : 0);
uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1],
flags);
}
for (i = 0; i < options.stdio_count; i++) {
if (uv__process_open_stream(&options.stdio[i], pipes + i * 2, i == 0)) {
int j;
/* Close all opened streams */
for (j = 0; j < i; j++) {
uv__process_close_stream(&options.stdio[j]);
}
if (stdout_pipe[0] >= 0) {
assert(options.stdout_stream);
assert(stdout_pipe[1] >= 0);
close(stdout_pipe[1]);
uv__nonblock(stdout_pipe[0], 1);
flags = UV_STREAM_READABLE |
(options.stdout_stream->ipc ? UV_STREAM_WRITABLE : 0);
uv__stream_open((uv_stream_t*)options.stdout_stream, stdout_pipe[0],
flags);
goto error;
}
}
if (stderr_pipe[0] >= 0) {
assert(options.stderr_stream);
assert(stderr_pipe[1] >= 0);
close(stderr_pipe[1]);
uv__nonblock(stderr_pipe[0], 1);
flags = UV_STREAM_READABLE |
(options.stderr_stream->ipc ? UV_STREAM_WRITABLE : 0);
uv__stream_open((uv_stream_t*)options.stderr_stream, stderr_pipe[0],
flags);
}
free(pipes);
return 0;
error:
uv__set_sys_error(process->loop, errno);
close(stdin_pipe[0]);
close(stdin_pipe[1]);
close(stdout_pipe[0]);
close(stdout_pipe[1]);
close(stderr_pipe[0]);
close(stderr_pipe[1]);
for (i = 0; i < options.stdio_count; i++) {
close(pipes[i * 2]);
close(pipes[i * 2 + 1]);
}
free(pipes);
return -1;
}

8
deps/uv/src/unix/sunos.c

@ -180,10 +180,10 @@ int uv_fs_event_init(uv_loop_t* loop,
/* We don't support any flags yet. */
assert(!flags);
if (loop->fs_fd == -1) {
if ((portfd = port_create()) == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
if ((portfd = port_create()) == -1) {
uv__set_sys_error(loop, errno);
return -1;
}
loop->fs_fd = portfd;
first_run = 1;
}

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

@ -82,25 +82,11 @@ int uv__tcp_connect6(uv_connect_t* req,
struct sockaddr_in6 address,
uv_connect_cb cb);
#ifndef UV_LEAN_AND_MEAN
UNUSED static int uv__has_active_handles(const uv_loop_t* loop) {
return !ngx_queue_empty(&loop->active_handles);
}
UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) {
return !ngx_queue_empty(&loop->active_reqs);
}
UNUSED static void uv__active_handle_add(uv_handle_t* h) {
ngx_queue_insert_tail(&h->loop->active_handles, &h->active_queue);
}
UNUSED static void uv__active_handle_rm(uv_handle_t* h) {
assert(uv__has_active_handles(h->loop));
ngx_queue_remove(&h->active_queue);
}
UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) {
ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue);
}
@ -110,37 +96,19 @@ UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) {
ngx_queue_remove(&req->active_queue);
}
#else /* UV_LEAN_AND_MEAN */
UNUSED static int uv__has_active_handles(const uv_loop_t* loop) {
return loop->active_handles > 0;
}
UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) {
return loop->active_reqs > 0;
}
UNUSED static void uv__active_handle_add(uv_handle_t* h) {
h->loop->active_handles++;
}
UNUSED static void uv__active_handle_rm(uv_handle_t* h) {
assert(h->loop->active_handles > 0);
h->loop->active_handles--;
}
UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) {
loop->active_reqs++;
(void) req;
}
UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) {
assert(loop->active_reqs > 0);
loop->active_reqs--;
(void) req;
}
#endif /* UV_LEAN_AND_MEAN */
#define uv__active_handle_add(h) uv__active_handle_add((uv_handle_t*)(h))
#define uv__active_handle_rm(h) uv__active_handle_rm((uv_handle_t*)(h))

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

@ -66,13 +66,8 @@ static void uv_loop_init(uv_loop_t* loop) {
uv_update_time(loop);
#ifndef UV_LEAN_AND_MEAN
ngx_queue_init(&loop->active_handles);
ngx_queue_init(&loop->active_reqs);
#else
loop->active_handles = 0;
loop->active_reqs = 0;
#endif
loop->pending_reqs_tail = NULL;
@ -215,18 +210,10 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
}
}
#ifndef UV_LEAN_AND_MEAN
# define UV_LOOP_ALIVE(loop) \
(!ngx_queue_empty(&(loop)->active_handles) || \
!ngx_queue_empty(&(loop)->active_reqs) || \
(loop)->endgame_handles != NULL)
#else
# define UV_LOOP_ALIVE(loop) \
((loop)->active_handles > 0 && \
(loop)->active_reqs > 0 && \
(loop)->endgame_handles != NULL)
#endif
#define UV_LOOP_ALIVE(loop) \
((loop)->active_handles > 0 || \
!ngx_queue_empty(&(loop)->active_reqs) || \
(loop)->endgame_handles != NULL)
#define UV_LOOP_ONCE(loop, poll) \
do { \

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

@ -22,6 +22,7 @@
#include "uv.h"
#include "internal.h"
#include <io.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
@ -639,26 +640,28 @@ static DWORD WINAPI spawn_failure(void* data) {
char* buf = NULL;
DWORD count, written;
WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
process->spawn_errno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR) &buf,
0,
NULL);
if (buf != NULL && count > 0) {
WriteFile(child_stderr, buf, count, &written, NULL);
LocalFree(buf);
} else {
WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
}
if (child_stderr != INVALID_HANDLE_VALUE) {
WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
process->spawn_errno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR) &buf,
0,
NULL);
if (buf != NULL && count > 0) {
WriteFile(child_stderr, buf, count, &written, NULL);
LocalFree(buf);
} else {
WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
}
FlushFileBuffers(child_stderr);
FlushFileBuffers(child_stderr);
}
/* Post completed */
POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
@ -673,7 +676,7 @@ static void close_child_stdio(uv_process_t* process) {
for (i = 0; i < ARRAY_SIZE(process->child_stdio); i++) {
handle = process->child_stdio[i];
if (handle != NULL && handle != INVALID_HANDLE_VALUE) {
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
process->child_stdio[i] = INVALID_HANDLE_VALUE;
}
@ -830,20 +833,10 @@ done:
}
static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
HANDLE handle;
HANDLE current_process = GetCurrentProcess();
handle = GetStdHandle(id);
static int duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
if (handle == NULL) {
*dup = NULL;
return 0;
} else if (handle == INVALID_HANDLE_VALUE) {
*dup = INVALID_HANDLE_VALUE;
uv__set_sys_error(loop, GetLastError());
return -1;
}
current_process = GetCurrentProcess();
if (!DuplicateHandle(current_process,
handle,
@ -861,23 +854,45 @@ static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
}
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);
}
int uv_spawn(uv_loop_t* loop, uv_process_t* process,
uv_process_options_t options) {
int err = 0, keep_child_stdio_open = 0;
wchar_t* path = NULL;
int size;
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;
STARTUPINFOW startup;
PROCESS_INFORMATION info;
uv_pipe_t* pipe;
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_SETGID |
@ -927,59 +942,60 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
application_path = application;
}
/* Create stdio pipes. */
if (options.stdin_stream) {
if (options.stdin_stream->ipc) {
err = uv_create_stdio_pipe_pair(
loop,
options.stdin_stream,
&child_stdio[0],
PIPE_ACCESS_DUPLEX,
GENERIC_READ | FILE_WRITE_ATTRIBUTES | GENERIC_WRITE,
1);
} else {
err = uv_create_stdio_pipe_pair(
loop,
options.stdin_stream,
&child_stdio[0],
PIPE_ACCESS_OUTBOUND,
GENERIC_READ | FILE_WRITE_ATTRIBUTES,
0);
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;
}
} else {
err = duplicate_std_handle(loop, STD_INPUT_HANDLE, &child_stdio[0]);
}
if (err) {
goto done;
}
if (options.stdout_stream) {
err = uv_create_stdio_pipe_pair(
loop, options.stdout_stream,
&child_stdio[1],
PIPE_ACCESS_INBOUND,
GENERIC_WRITE,
0);
} else {
err = duplicate_std_handle(loop, STD_OUTPUT_HANDLE, &child_stdio[1]);
}
if (err) {
goto done;
}
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 (options.stderr_stream) {
err = uv_create_stdio_pipe_pair(
loop,
options.stderr_stream,
&child_stdio[2],
PIPE_ACCESS_INBOUND,
GENERIC_WRITE,
0);
} else {
err = duplicate_std_handle(loop, STD_ERROR_HANDLE, &child_stdio[2]);
}
if (err) {
goto done;
if (err) {
goto done;
}
}
startup.cb = sizeof(startup);
@ -1007,9 +1023,11 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
if (options.stdin_stream &&
options.stdin_stream->ipc) {
options.stdin_stream->ipc_pid = info.dwProcessId;
if (options.stdio_count > 0 &&
options.stdio[0].flags & UV_CREATE_PIPE &&
options.stdio[0].data.stream->type == UV_NAMED_PIPE &&
((uv_pipe_t*)options.stdio[0].data.stream)->ipc) {
((uv_pipe_t*)options.stdio[0].data.stream)->ipc_pid = info.dwProcessId;
}
/* Setup notifications for when the child process exits. */

8
deps/uv/test/benchmark-spawn.c

@ -101,6 +101,7 @@ void on_read(uv_stream_t* pipe, ssize_t nread, uv_buf_t buf) {
static void spawn() {
uv_stdio_container_t stdio[2];
int r;
ASSERT(process_open == 0);
@ -114,7 +115,12 @@ static void spawn() {
options.exit_cb = exit_cb;
uv_pipe_init(loop, &out, 0);
options.stdout_stream = &out;
options.stdio = stdio;
options.stdio_count = 2;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
r = uv_spawn(loop, &process, options);
ASSERT(r == 0);

5
deps/uv/test/runner-win.c

@ -19,6 +19,7 @@
* IN THE SOFTWARE.
*/
#include <fcntl.h>
#include <io.h>
#include <malloc.h>
#include <stdio.h>
@ -44,6 +45,10 @@ void platform_init(int argc, char **argv) {
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
_setmode(0, _O_BINARY);
_setmode(1, _O_BINARY);
_setmode(2, _O_BINARY);
/* Disable stdio output buffering. */
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);

10
deps/uv/test/test-ipc.c

@ -200,6 +200,7 @@ void spawn_helper(uv_pipe_t* channel,
char exepath[1024];
char* args[3];
int r;
uv_stdio_container_t stdio[1];
r = uv_pipe_init(uv_default_loop(), channel, 1);
ASSERT(r == 0);
@ -218,7 +219,12 @@ void spawn_helper(uv_pipe_t* channel,
options.file = exepath;
options.args = args;
options.exit_cb = exit_cb;
options.stdin_stream = channel;
options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE |
UV_READABLE_PIPE | UV_WRITABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*)channel;
options.stdio_count = 1;
r = uv_spawn(uv_default_loop(), process, options);
ASSERT(r == 0);
@ -611,4 +617,4 @@ int ipc_helper_tcp_connection() {
ASSERT(close_cb_called == 4);
return 0;
}
}

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

@ -123,6 +123,7 @@ TEST_DECLARE (spawn_and_kill_with_std)
TEST_DECLARE (spawn_and_ping)
TEST_DECLARE (spawn_setuid_fails)
TEST_DECLARE (spawn_setgid_fails)
TEST_DECLARE (spawn_stdout_to_file)
TEST_DECLARE (kill)
TEST_DECLARE (fs_file_noent)
TEST_DECLARE (fs_file_nametoolong)
@ -334,6 +335,7 @@ TASK_LIST_START
TEST_ENTRY (spawn_and_ping)
TEST_ENTRY (spawn_setuid_fails)
TEST_ENTRY (spawn_setgid_fails)
TEST_ENTRY (spawn_stdout_to_file)
TEST_ENTRY (kill)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)

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

@ -21,6 +21,7 @@
#include "uv.h"
#include "task.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -167,11 +168,16 @@ TEST_IMPL(spawn_exit_code) {
TEST_IMPL(spawn_stdout) {
int r;
uv_pipe_t out;
uv_stdio_container_t stdio[2];
init_process_options("spawn_helper2", exit_cb);
uv_pipe_init(uv_default_loop(), &out, 0);
options.stdout_stream = &out;
options.stdio = stdio;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio_count = 2;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
@ -185,7 +191,59 @@ TEST_IMPL(spawn_stdout) {
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
printf("output is: %s", output);
ASSERT(strcmp("hello world\n", output) == 0 || strcmp("hello world\r\n", output) == 0);
ASSERT(strcmp("hello world\n", output) == 0);
return 0;
}
TEST_IMPL(spawn_stdout_to_file) {
int r;
uv_file file;
uv_fs_t fs_req;
uv_stdio_container_t stdio[2];
/* Setup. */
unlink("stdout_file");
init_process_options("spawn_helper2", exit_cb);
r = uv_fs_open(uv_default_loop(), &fs_req, "stdout_file", O_CREAT | O_RDWR,
S_IREAD | S_IWRITE, NULL);
ASSERT(r != -1);
uv_fs_req_cleanup(&fs_req);
file = r;
options.stdio = stdio;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_RAW_FD;
options.stdio[1].data.fd = file;
options.stdio_count = 2;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
r = uv_run(uv_default_loop());
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 1);
r = uv_fs_read(uv_default_loop(), &fs_req, file, output, sizeof(output),
0, NULL);
ASSERT(r == 12);
uv_fs_req_cleanup(&fs_req);
r = uv_fs_close(uv_default_loop(), &fs_req, file, NULL);
ASSERT(r == 0);
uv_fs_req_cleanup(&fs_req);
printf("output is: %s", output);
ASSERT(strcmp("hello world\n", output) == 0);
/* Cleanup. */
unlink("stdout_file");
return 0;
}
@ -197,14 +255,19 @@ TEST_IMPL(spawn_stdin) {
uv_pipe_t in;
uv_write_t write_req;
uv_buf_t buf;
uv_stdio_container_t stdio[2];
char buffer[] = "hello-from-spawn_stdin";
init_process_options("spawn_helper3", exit_cb);
uv_pipe_init(uv_default_loop(), &out, 0);
uv_pipe_init(uv_default_loop(), &in, 0);
options.stdout_stream = &out;
options.stdin_stream = &in;
options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*)&in;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio_count = 2;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
@ -259,6 +322,7 @@ TEST_IMPL(spawn_and_kill_with_std) {
char message[] = "Nancy's joining me because the message this evening is "
"not my message but ours.";
uv_buf_t buf;
uv_stdio_container_t stdio[3];
init_process_options("spawn_helper4", kill_cb);
@ -271,9 +335,14 @@ TEST_IMPL(spawn_and_kill_with_std) {
r = uv_pipe_init(uv_default_loop(), &err, 0);
ASSERT(r == 0);
options.stdin_stream = &in;
options.stdout_stream = &out;
options.stderr_stream = &err;
options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*)&in;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[2].data.stream = (uv_stream_t*)&err;
options.stdio_count = 3;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
@ -308,6 +377,7 @@ TEST_IMPL(spawn_and_ping) {
uv_write_t write_req;
uv_pipe_t in, out;
uv_buf_t buf;
uv_stdio_container_t stdio[2];
int r;
init_process_options("spawn_helper3", exit_cb);
@ -315,8 +385,12 @@ TEST_IMPL(spawn_and_ping) {
uv_pipe_init(uv_default_loop(), &out, 0);
uv_pipe_init(uv_default_loop(), &in, 0);
options.stdout_stream = &out;
options.stdin_stream = &in;
options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*)&in;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio_count = 2;
r = uv_spawn(uv_default_loop(), &process, options);
ASSERT(r == 0);
@ -384,11 +458,16 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
uv_pipe_t out;
char name[64];
HANDLE pipe_handle;
uv_stdio_container_t stdio[2];
init_process_options("spawn_helper2", exit_cb);
uv_pipe_init(uv_default_loop(), &out, 0);
options.stdout_stream = &out;
options.stdio = stdio;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio_count = 2;
/* Create a pipe that'll cause a collision. */
_snprintf(name, sizeof(name), "\\\\.\\pipe\\uv\\%p-%d", &out, GetCurrentProcessId());
@ -414,7 +493,7 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
printf("output is: %s", output);
ASSERT(strcmp("hello world\n", output) == 0 || strcmp("hello world\r\n", output) == 0);
ASSERT(strcmp("hello world\n", output) == 0);
return 0;
}

11
deps/uv/test/test-stdio-over-pipes.c

@ -115,14 +115,21 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t rdbuf) {
TEST_IMPL(stdio_over_pipes) {
int r;
uv_process_t process;
uv_stdio_container_t stdio[2];
loop = uv_default_loop();
init_process_options("stdio_over_pipes_helper", exit_cb);
uv_pipe_init(loop, &out, 0);
options.stdout_stream = &out;
uv_pipe_init(loop, &in, 0);
options.stdin_stream = &in;
options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*)&in;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio_count = 2;
r = uv_spawn(loop, &process, options);
ASSERT(r == 0);

24
src/process_wrap.cc

@ -169,12 +169,24 @@ class ProcessWrap : public HandleWrap {
options.env[envc] = NULL;
}
uv_stdio_container_t stdio[3];
memset(stdio, 0, sizeof(stdio));
options.stdio = stdio;
options.stdio_count = 3;
options.stdio[0].flags = UV_IGNORE;
options.stdio[1].flags = UV_IGNORE;
options.stdio[2].flags = UV_IGNORE;
// options.stdin_stream
Local<Value> stdin_stream_v = js_options->Get(
String::NewSymbol("stdinStream"));
if (!stdin_stream_v.IsEmpty() && stdin_stream_v->IsObject()) {
PipeWrap* stdin_wrap = PipeWrap::Unwrap(stdin_stream_v->ToObject());
options.stdin_stream = stdin_wrap->UVHandle();
options.stdio[0].flags = static_cast<uv_stdio_flags>(
UV_CREATE_PIPE | UV_WRITABLE_PIPE);
options.stdio[0].data.stream = reinterpret_cast<uv_stream_t*>(
stdin_wrap->UVHandle());
}
// options.stdout_stream
@ -182,7 +194,10 @@ class ProcessWrap : public HandleWrap {
String::NewSymbol("stdoutStream"));
if (!stdout_stream_v.IsEmpty() && stdout_stream_v->IsObject()) {
PipeWrap* stdout_wrap = PipeWrap::Unwrap(stdout_stream_v->ToObject());
options.stdout_stream = stdout_wrap->UVHandle();
options.stdio[1].flags = static_cast<uv_stdio_flags>(
UV_CREATE_PIPE | UV_READABLE_PIPE);
options.stdio[1].data.stream = reinterpret_cast<uv_stream_t*>(
stdout_wrap->UVHandle());
}
// options.stderr_stream
@ -190,7 +205,10 @@ class ProcessWrap : public HandleWrap {
String::NewSymbol("stderrStream"));
if (!stderr_stream_v.IsEmpty() && stderr_stream_v->IsObject()) {
PipeWrap* stderr_wrap = PipeWrap::Unwrap(stderr_stream_v->ToObject());
options.stderr_stream = stderr_wrap->UVHandle();
options.stdio[2].flags = static_cast<uv_stdio_flags>(
UV_CREATE_PIPE | UV_READABLE_PIPE);
options.stdio[2].data.stream = reinterpret_cast<uv_stream_t*>(
stderr_wrap->UVHandle());
}
// options.windows_verbatim_arguments

Loading…
Cancel
Save