summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFedor Indutny <fedor.indutny@gmail.com>2012-05-28 23:52:34 +0400
committerFedor Indutny <fedor.indutny@gmail.com>2012-05-29 18:26:40 +0400
commit761e0c460a8e9a40cd1126cf0ba354e50e38d6da (patch)
tree314a084790dd95dcea5ea4928321a9d47c3aaa93
parentfa9aa1c961125f5c5527c7b5e3720eadf84a979f (diff)
downloadandroid-node-v8-761e0c460a8e9a40cd1126cf0ba354e50e38d6da.tar.gz
android-node-v8-761e0c460a8e9a40cd1126cf0ba354e50e38d6da.tar.bz2
android-node-v8-761e0c460a8e9a40cd1126cf0ba354e50e38d6da.zip
deps: upgrade libuv to 7556590
-rw-r--r--deps/uv/include/uv.h55
-rw-r--r--deps/uv/src/unix/core.c3
-rw-r--r--deps/uv/src/unix/internal.h6
-rw-r--r--deps/uv/src/unix/loop.c6
-rw-r--r--deps/uv/src/unix/process.c204
-rw-r--r--deps/uv/src/unix/sunos.c8
-rw-r--r--deps/uv/src/uv-common.h32
-rw-r--r--deps/uv/src/win/core.c21
-rw-r--r--deps/uv/src/win/process.c192
-rw-r--r--deps/uv/test/benchmark-spawn.c8
-rw-r--r--deps/uv/test/runner-win.c5
-rw-r--r--deps/uv/test/test-ipc.c10
-rw-r--r--deps/uv/test/test-list.h2
-rw-r--r--deps/uv/test/test-spawn.c101
-rw-r--r--deps/uv/test/test-stdio-over-pipes.c11
-rw-r--r--src/process_wrap.cc24
16 files changed, 409 insertions, 279 deletions
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index f784546795..f9ffbaf4cb 100644
--- a/deps/uv/include/uv.h
+++ b/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
};
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index 24d10a10a5..b3f232176a 100644
--- a/deps/uv/src/unix/core.c
+++ b/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);
}
diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h
index 63a2a8bf96..eb5be60527 100644
--- a/deps/uv/src/unix/internal.h
+++ b/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))
diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c
index 14743daaf8..70057656bc 100644
--- a/deps/uv/src/unix/loop.c
+++ b/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);
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
index bccaf17147..2efe896ace 100644
--- a/deps/uv/src/unix/process.c
+++ b/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;
}
diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c
index f341297bba..3cf214c04c 100644
--- a/deps/uv/src/unix/sunos.c
+++ b/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;
}
diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
index cede20ba6d..6e484ef547 100644
--- a/deps/uv/src/uv-common.h
+++ b/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))
diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c
index f32b9162a2..4f546eefcc 100644
--- a/deps/uv/src/win/core.c
+++ b/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 { \
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 481b945c97..e3d8a1fd94 100644
--- a/deps/uv/src/win/process.c
+++ b/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. */
diff --git a/deps/uv/test/benchmark-spawn.c b/deps/uv/test/benchmark-spawn.c
index d34f42b9fe..74cc3d238f 100644
--- a/deps/uv/test/benchmark-spawn.c
+++ b/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);
diff --git a/deps/uv/test/runner-win.c b/deps/uv/test/runner-win.c
index e758dd1dd3..ad36719c8f 100644
--- a/deps/uv/test/runner-win.c
+++ b/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);
diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c
index 1ea0e7f963..61add0b4b8 100644
--- a/deps/uv/test/test-ipc.c
+++ b/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;
-} \ No newline at end of file
+}
diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h
index 63683f28ed..ffb1fe2346 100644
--- a/deps/uv/test/test-list.h
+++ b/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)
diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c
index ccb9538f90..25863de6a5 100644
--- a/deps/uv/test/test-spawn.c
+++ b/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;
}
diff --git a/deps/uv/test/test-stdio-over-pipes.c b/deps/uv/test/test-stdio-over-pipes.c
index 0a3f04c692..7603027fb8 100644
--- a/deps/uv/test/test-stdio-over-pipes.c
+++ b/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);
diff --git a/src/process_wrap.cc b/src/process_wrap.cc
index 52b2120b47..ce29853565 100644
--- a/src/process_wrap.cc
+++ b/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