summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2012-06-05 15:45:46 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2012-06-05 16:48:17 +0200
commit0a2076b26ac0dee453d664e0d0d6a0cc934bd579 (patch)
tree3b47e7a48d5ab6e9994835be430a0d333218228e
parent27061cc9f45afbc4ddc1efa8bed1ea22df7cb0f4 (diff)
downloadnode-0a2076b26ac0dee453d664e0d0d6a0cc934bd579.tar.gz
deps: upgrade libuv to c8c9fe1
-rw-r--r--deps/uv/include/uv-private/uv-unix.h3
-rw-r--r--deps/uv/include/uv-private/uv-win.h2
-rw-r--r--deps/uv/include/uv.h11
-rw-r--r--deps/uv/src/unix/core.c7
-rw-r--r--deps/uv/src/unix/process.c113
-rw-r--r--deps/uv/src/unix/stream.c35
-rw-r--r--deps/uv/src/unix/thread.c107
-rw-r--r--deps/uv/src/unix/udp.c15
-rw-r--r--deps/uv/src/uv-common.c2
-rw-r--r--deps/uv/src/uv-common.h2
-rw-r--r--deps/uv/src/win/async.c2
-rw-r--r--deps/uv/src/win/core.c21
-rw-r--r--deps/uv/src/win/fs-event.c8
-rw-r--r--deps/uv/src/win/fs.c2
-rw-r--r--deps/uv/src/win/getaddrinfo.c1
-rw-r--r--deps/uv/src/win/handle-inl.h150
-rw-r--r--deps/uv/src/win/handle.c80
-rw-r--r--deps/uv/src/win/internal.h116
-rw-r--r--deps/uv/src/win/loop-watcher.c1
-rw-r--r--deps/uv/src/win/pipe.c3
-rw-r--r--deps/uv/src/win/poll.c67
-rw-r--r--deps/uv/src/win/process.c68
-rw-r--r--deps/uv/src/win/req-inl.h225
-rw-r--r--deps/uv/src/win/req.c144
-rw-r--r--deps/uv/src/win/stream-inl.h67
-rw-r--r--deps/uv/src/win/stream.c37
-rw-r--r--deps/uv/src/win/tcp.c4
-rw-r--r--deps/uv/src/win/thread.c39
-rw-r--r--deps/uv/src/win/threadpool.c1
-rw-r--r--deps/uv/src/win/timer.c47
-rw-r--r--deps/uv/src/win/tty.c5
-rw-r--r--deps/uv/src/win/udp.c3
-rw-r--r--deps/uv/src/win/util.c340
-rw-r--r--deps/uv/src/win/winapi.c8
-rw-r--r--deps/uv/src/win/winapi.h25
-rw-r--r--deps/uv/test/run-tests.c14
-rw-r--r--deps/uv/test/test-list.h16
-rw-r--r--deps/uv/test/test-poll-close.c77
-rw-r--r--deps/uv/test/test-poll.c6
-rw-r--r--deps/uv/test/test-semaphore.c111
-rw-r--r--deps/uv/test/test-spawn.c21
-rw-r--r--deps/uv/test/test-tcp-connect-error-after-write.c95
-rw-r--r--deps/uv/test/test-tcp-shutdown-after-write.c129
-rw-r--r--deps/uv/test/test-tcp-writealot.c6
-rw-r--r--deps/uv/uv.gyp7
45 files changed, 1564 insertions, 679 deletions
diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h
index ae9f5fb3d..3b9619c87 100644
--- a/deps/uv/include/uv-private/uv-unix.h
+++ b/deps/uv/include/uv-private/uv-unix.h
@@ -35,6 +35,8 @@
#include <netdb.h>
#include <pwd.h>
#include <termios.h>
+
+#include <semaphore.h>
#include <pthread.h>
#if __sun
@@ -58,6 +60,7 @@ typedef pthread_once_t uv_once_t;
typedef pthread_t uv_thread_t;
typedef pthread_mutex_t uv_mutex_t;
typedef pthread_rwlock_t uv_rwlock_t;
+typedef sem_t uv_sem_t;
/* Platform-specific definitions for uv_spawn support. */
typedef gid_t uv_gid_t;
diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h
index 3b091b93d..259984944 100644
--- a/deps/uv/include/uv-private/uv-win.h
+++ b/deps/uv/include/uv-private/uv-win.h
@@ -169,6 +169,8 @@ typedef SOCKET uv_os_sock_t;
typedef HANDLE uv_thread_t;
+typedef HANDLE uv_sem_t;
+
typedef CRITICAL_SECTION uv_mutex_t;
typedef union {
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index 2ddcfa7ca..e52ae6431 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -432,7 +432,7 @@ UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
* base and len members of the uv_buf_t struct. The user is responsible for
* freeing base after the uv_buf_t is done. Return struct passed by value.
*/
-UV_EXTERN uv_buf_t uv_buf_init(char* base, size_t len);
+UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
/*
@@ -1624,6 +1624,15 @@ UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock);
UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
+/*
+ * Same goes for the semaphore functions.
+ */
+UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
+UV_EXTERN void uv_sem_destroy(uv_sem_t* sem);
+UV_EXTERN void uv_sem_post(uv_sem_t* sem);
+UV_EXTERN void uv_sem_wait(uv_sem_t* sem);
+UV_EXTERN int uv_sem_trywait(uv_sem_t* sem);
+
/* Runs a function once and only once. Concurrent calls to uv_once() with the
* same guard will block all callers except one (it's unspecified which one).
* The guard should be initialized statically with the UV_ONCE_INIT macro.
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index 1802d2f1b..37d03d3eb 100644
--- a/deps/uv/src/unix/core.c
+++ b/deps/uv/src/unix/core.c
@@ -604,6 +604,13 @@ static void uv__io_rw(struct ev_loop* ev, ev_io* w, int events) {
uv__io_t* handle = container_of(w, uv__io_t, io_watcher);
u.data = handle->io_watcher.data;
u.cb(loop, handle, events & (EV_READ|EV_WRITE|EV_ERROR));
+
+ /* The callback may have closed all active handles. Stop libev from entering
+ * the epoll_wait/kevent/port_getn/etc. syscall if that's the case, it would
+ * hang indefinitely.
+ */
+ if (loop->active_handles == 0)
+ ev_break(loop->ev, EVBREAK_ONE);
}
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
index 7584d9280..d3eb998c1 100644
--- a/deps/uv/src/unix/process.c
+++ b/deps/uv/src/unix/process.c
@@ -28,6 +28,7 @@
#include <poll.h>
#include <unistd.h>
#include <stdio.h>
+#include <fcntl.h>
#ifdef __APPLE__
# include <TargetConditionals.h>
@@ -217,6 +218,68 @@ static void uv__process_close_stream(uv_stdio_container_t* container) {
uv__stream_close((uv_stream_t*)container->data.stream);
}
+
+static void uv__process_child_init(uv_process_options_t options,
+ int stdio_count,
+ int* pipes) {
+ int i;
+
+ if (options.flags & UV_PROCESS_DETACHED) {
+ setsid();
+ }
+
+ /* Dup fds */
+ for (i = 0; i < 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);
+ } else if (i < 3) {
+ /* `/dev/null` stdin, stdout, stderr even if they've flag UV_IGNORE */
+ use_fd = open("/dev/null", i == 0 ? O_RDONLY : O_RDWR);
+
+ if (use_fd < 0) {
+ perror("failed to open stdio");
+ _exit(127);
+ }
+ } else {
+ continue;
+ }
+
+ if (i != use_fd) {
+ dup2(use_fd, i);
+ close(use_fd);
+ }
+ }
+
+ if (options.cwd && chdir(options.cwd)) {
+ perror("chdir()");
+ _exit(127);
+ }
+
+ if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
+ perror("setgid()");
+ _exit(127);
+ }
+
+ if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
+ perror("setuid()");
+ _exit(127);
+ }
+
+ environ = options.env;
+
+ execvp(options.file, options.args);
+ perror("execvp()");
+ _exit(127);
+}
+
+
#ifndef SPAWN_WAIT_EXEC
# define SPAWN_WAIT_EXEC 1
#endif
@@ -229,7 +292,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
*/
char** save_our_env = environ;
- int* pipes = malloc(2 * options.stdio_count * sizeof(int));
+ int stdio_count = options.stdio_count < 3 ? 3 : options.stdio_count;
+ int* pipes = malloc(2 * stdio_count * sizeof(int));
#if SPAWN_WAIT_EXEC
int signal_pipe[2] = { -1, -1 };
@@ -258,7 +322,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
process->exit_cb = options.exit_cb;
/* Init pipe pairs */
- for (i = 0; i < options.stdio_count; i++) {
+ for (i = 0; i < stdio_count; i++) {
pipes[i * 2] = -1;
pipes[i * 2 + 1] = -1;
}
@@ -308,49 +372,8 @@ 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++) {
- /*
- * 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);
- }
- }
+ uv__process_child_init(options, stdio_count, pipes);
- if (options.cwd && chdir(options.cwd)) {
- perror("chdir()");
- _exit(127);
- }
-
- if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
- perror("setgid()");
- _exit(127);
- }
-
- if ((options.flags & UV_PROCESS_SETUID) && setuid(options.uid)) {
- perror("setuid()");
- _exit(127);
- }
-
- environ = options.env;
-
- execvp(options.file, options.args);
- perror("execvp()");
- _exit(127);
/* Execution never reaches here. */
}
@@ -399,7 +422,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
error:
uv__set_sys_error(process->loop, errno);
- for (i = 0; i < options.stdio_count; i++) {
+ for (i = 0; i < stdio_count; i++) {
close(pipes[i * 2]);
close(pipes[i * 2 + 1]);
}
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 9091b90fb..602e94889 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -561,12 +561,19 @@ static void uv__read(uv_stream_t* stream) {
struct msghdr msg;
struct cmsghdr* cmsg;
char cmsg_space[64];
+ int count;
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
/* XXX: Maybe instead of having UV_STREAM_READING we just test if
* tcp->read_cb is NULL or not?
*/
- while ((stream->read_cb || stream->read2_cb) &&
- stream->flags & UV_STREAM_READING) {
+ while ((stream->read_cb || stream->read2_cb)
+ && (stream->flags & UV_STREAM_READING)
+ && (count-- > 0)) {
assert(stream->alloc_cb);
buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024);
@@ -890,42 +897,36 @@ int uv_write2(uv_write_t* req, uv_stream_t* stream, uv_buf_t bufs[], int bufcnt,
req->send_handle = send_handle;
ngx_queue_init(&req->queue);
- if (bufcnt <= UV_REQ_BUFSML_SIZE) {
+ if (bufcnt <= UV_REQ_BUFSML_SIZE)
req->bufs = req->bufsml;
- }
- else {
+ else
req->bufs = malloc(sizeof(uv_buf_t) * bufcnt);
- }
memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t));
req->bufcnt = bufcnt;
-
- /*
- * fprintf(stderr, "cnt: %d bufs: %p bufsml: %p\n", bufcnt, req->bufs, req->bufsml);
- */
-
req->write_index = 0;
stream->write_queue_size += uv__buf_count(bufs, bufcnt);
/* Append the request to write_queue. */
ngx_queue_insert_tail(&stream->write_queue, &req->queue);
- assert(!ngx_queue_empty(&stream->write_queue));
-
/* If the queue was empty when this function began, we should attempt to
* do the write immediately. Otherwise start the write_watcher and wait
* for the fd to become writable.
*/
- if (empty_queue) {
+ if (stream->connect_req) {
+ /* Still connecting, do nothing. */
+ }
+ else if (empty_queue) {
uv__write(stream);
- } else {
+ }
+ else {
/*
* blocking streams should never have anything in the queue.
* if this assert fires then somehow the blocking stream isn't being
- * sufficently flushed in uv__write.
+ * sufficiently flushed in uv__write.
*/
assert(!(stream->flags & UV_STREAM_BLOCKING));
-
uv__io_start(stream->loop, &stream->write_watcher);
}
diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c
index 4a987a715..cd4e3333b 100644
--- a/deps/uv/src/unix/thread.c
+++ b/deps/uv/src/unix/thread.c
@@ -26,19 +26,6 @@
#include <assert.h>
#include <errno.h>
-#ifdef NDEBUG
-# define CHECK(r) ((void) (r))
-#else
-# include <stdio.h>
-# include <stdlib.h>
-# define CHECK(r) \
- do { \
- int __r = (r); \
- if (__r) errno = __r, perror(#r), abort(); \
- } \
- while (0)
-#endif
-
int uv_thread_join(uv_thread_t *tid) {
if (pthread_join(*tid, NULL))
@@ -49,20 +36,40 @@ int uv_thread_join(uv_thread_t *tid) {
int uv_mutex_init(uv_mutex_t* mutex) {
+#ifdef NDEBUG
if (pthread_mutex_init(mutex, NULL))
return -1;
else
return 0;
+#else
+ pthread_mutexattr_t attr;
+ int r;
+
+ if (pthread_mutexattr_init(&attr))
+ abort();
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
+ abort();
+
+ r = pthread_mutex_init(mutex, &attr);
+
+ if (pthread_mutexattr_destroy(&attr))
+ abort();
+
+ return r ? -1 : 0;
+#endif
}
void uv_mutex_destroy(uv_mutex_t* mutex) {
- CHECK(pthread_mutex_destroy(mutex));
+ if (pthread_mutex_destroy(mutex))
+ abort();
}
void uv_mutex_lock(uv_mutex_t* mutex) {
- CHECK(pthread_mutex_lock(mutex));
+ if (pthread_mutex_lock(mutex))
+ abort();
}
@@ -72,7 +79,7 @@ int uv_mutex_trylock(uv_mutex_t* mutex) {
r = pthread_mutex_trylock(mutex);
if (r && r != EAGAIN)
- CHECK(r);
+ abort();
if (r)
return -1;
@@ -82,7 +89,8 @@ int uv_mutex_trylock(uv_mutex_t* mutex) {
void uv_mutex_unlock(uv_mutex_t* mutex) {
- CHECK(pthread_mutex_unlock(mutex));
+ if (pthread_mutex_unlock(mutex))
+ abort();
}
@@ -95,12 +103,14 @@ int uv_rwlock_init(uv_rwlock_t* rwlock) {
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
- CHECK(pthread_rwlock_destroy(rwlock));
+ if (pthread_rwlock_destroy(rwlock))
+ abort();
}
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
- CHECK(pthread_rwlock_rdlock(rwlock));
+ if (pthread_rwlock_rdlock(rwlock))
+ abort();
}
@@ -110,7 +120,7 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
r = pthread_rwlock_tryrdlock(rwlock);
if (r && r != EAGAIN)
- CHECK(r);
+ abort();
if (r)
return -1;
@@ -120,12 +130,14 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
- CHECK(pthread_rwlock_unlock(rwlock));
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
}
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
- CHECK(pthread_rwlock_wrlock(rwlock));
+ if (pthread_rwlock_wrlock(rwlock))
+ abort();
}
@@ -135,7 +147,7 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
r = pthread_rwlock_trywrlock(rwlock);
if (r && r != EAGAIN)
- CHECK(r);
+ abort();
if (r)
return -1;
@@ -145,10 +157,55 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
- CHECK(pthread_rwlock_unlock(rwlock));
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
}
void uv_once(uv_once_t* guard, void (*callback)(void)) {
- CHECK(pthread_once(guard, callback));
+ if (pthread_once(guard, callback))
+ abort();
+}
+
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ return sem_init(sem, 0, value);
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (sem_destroy(sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (sem_post(sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_wait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_trywait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r && errno != EAGAIN)
+ abort();
+
+ return r;
}
diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c
index 523d2823d..9f87060ae 100644
--- a/deps/uv/src/unix/udp.c
+++ b/deps/uv/src/unix/udp.c
@@ -196,6 +196,7 @@ static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) {
ssize_t nread;
uv_buf_t buf;
int flags;
+ int count;
handle = container_of(w, uv_udp_t, read_watcher);
assert(handle->type == UV_UDP);
@@ -204,15 +205,20 @@ static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) {
assert(handle->recv_cb != NULL);
assert(handle->alloc_cb != NULL);
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ memset(&h, 0, sizeof(h));
+ h.msg_name = &peer;
+
do {
- /* FIXME: hoist alloc_cb out the loop but for now follow uv__read() */
buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024);
assert(buf.len > 0);
assert(buf.base != NULL);
- memset(&h, 0, sizeof h);
- h.msg_name = &peer;
- h.msg_namelen = sizeof peer;
+ h.msg_namelen = sizeof(peer);
h.msg_iov = (struct iovec*)&buf;
h.msg_iovlen = 1;
@@ -246,6 +252,7 @@ static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, int revents) {
}
/* recv_cb callback may decide to pause or close the handle */
while (nread != -1
+ && count-- > 0
&& handle->fd != -1
&& handle->recv_cb != NULL);
}
diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c
index 761133a63..48f850c73 100644
--- a/deps/uv/src/uv-common.c
+++ b/deps/uv/src/uv-common.c
@@ -87,7 +87,7 @@ size_t uv_strlcat(char* dst, const char* src, size_t size) {
}
-uv_buf_t uv_buf_init(char* base, size_t len) {
+uv_buf_t uv_buf_init(char* base, unsigned int len) {
uv_buf_t buf;
buf.base = base;
buf.len = len;
diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h
index 4a721ef97..c86cb7daa 100644
--- a/deps/uv/src/uv-common.h
+++ b/deps/uv/src/uv-common.h
@@ -42,8 +42,10 @@
#ifdef _MSC_VER
# define UNUSED /* empty */
+# define INLINE __inline
#else
# define UNUSED __attribute__((unused))
+# define INLINE inline
#endif
diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c
index 87f55296e..184802370 100644
--- a/deps/uv/src/win/async.c
+++ b/deps/uv/src/win/async.c
@@ -23,6 +23,8 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
/* Atomic set operation on char */
diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c
index 78c9fac54..7a3558038 100644
--- a/deps/uv/src/win/core.c
+++ b/deps/uv/src/win/core.c
@@ -28,6 +28,8 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
/* The only event loop we support right now */
@@ -43,17 +45,21 @@ static void uv_init(void) {
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
+ /* Fetch winapi function pointers. This must be done first because other */
+ /* intialization code might need these function pointers to be loaded. */
+ uv_winapi_init();
+
/* Initialize winsock */
uv_winsock_init();
- /* Fetch winapi function pointers */
- uv_winapi_init();
-
/* Initialize FS */
uv_fs_init();
/* Initialize console */
uv_console_init();
+
+ /* Initialize utilities */
+ uv__util_init();
}
@@ -100,13 +106,18 @@ static void uv_loop_init(uv_loop_t* loop) {
static void uv_default_loop_init(void) {
/* Initialize libuv itself first */
- uv_once(&uv_init_guard_, uv_init);
+ uv__once_init();
/* Initialize the main loop */
uv_loop_init(&uv_default_loop_);
}
+void uv__once_init(void) {
+ uv_once(&uv_init_guard_, uv_init);
+}
+
+
uv_loop_t* uv_default_loop(void) {
uv_once(&uv_default_loop_init_guard_, uv_default_loop_init);
return &uv_default_loop_;
@@ -117,7 +128,7 @@ uv_loop_t* uv_loop_new(void) {
uv_loop_t* loop;
/* Initialize libuv itself first */
- uv_once(&uv_init_guard_, uv_init);
+ uv__once_init();
loop = (uv_loop_t*)malloc(sizeof(uv_loop_t));
diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c
index 30a571a7c..ccf941d1b 100644
--- a/deps/uv/src/win/fs-event.c
+++ b/deps/uv/src/win/fs-event.c
@@ -19,15 +19,17 @@
* IN THE SOFTWARE.
*/
-#include "uv.h"
-#include "internal.h"
-
#include <assert.h>
#include <malloc.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
const unsigned int uv_directory_watcher_buffer_size = 4096;
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index 5df4829d8..b6b973939 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -32,6 +32,8 @@
#include "uv.h"
#include "internal.h"
+#include "req-inl.h"
+
#define UV_FS_ASYNC_QUEUED 0x0001
#define UV_FS_FREE_PATH 0x0002
diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c
index bdfe1bb93..41e7a4aa2 100644
--- a/deps/uv/src/win/getaddrinfo.c
+++ b/deps/uv/src/win/getaddrinfo.c
@@ -24,6 +24,7 @@
#include "uv.h"
#include "internal.h"
+#include "req-inl.h"
/*
diff --git a/deps/uv/src/win/handle-inl.h b/deps/uv/src/win/handle-inl.h
new file mode 100644
index 000000000..f069dd192
--- /dev/null
+++ b/deps/uv/src/win/handle-inl.h
@@ -0,0 +1,150 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_HANDLE_INL_H_
+#define UV_WIN_HANDLE_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define DECREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if (--(handle)->activecnt == 0 && \
+ !((handle)->flags & UV_HANDLE_CLOSING)) { \
+ uv__handle_stop((handle)); \
+ } \
+ assert((handle)->activecnt >= 0); \
+ } while (0)
+
+
+#define INCREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if ((handle)->activecnt++ == 0) { \
+ uv__handle_start((handle)); \
+ } \
+ assert((handle)->activecnt > 0); \
+ } while (0)
+
+
+#define DECREASE_PENDING_REQ_COUNT(handle) \
+ do { \
+ assert(handle->reqs_pending > 0); \
+ handle->reqs_pending--; \
+ \
+ if (handle->flags & UV_HANDLE_CLOSING && \
+ handle->reqs_pending == 0) { \
+ uv_want_endgame(loop, (uv_handle_t*)handle); \
+ } \
+ } 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)
+
+
+INLINE static void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) {
+ handle->loop = loop;
+ handle->flags = UV__HANDLE_REF;
+ ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue);
+
+ loop->counters.handle_init++;
+}
+
+
+INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
+ handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
+
+ handle->endgame_next = loop->endgame_handles;
+ loop->endgame_handles = handle;
+ }
+}
+
+
+INLINE static void uv_process_endgames(uv_loop_t* loop) {
+ uv_handle_t* handle;
+
+ while (loop->endgame_handles) {
+ handle = loop->endgame_handles;
+ loop->endgame_handles = handle->endgame_next;
+
+ handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
+
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_endgame(loop, (uv_tcp_t*) handle);
+ break;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_endgame(loop, (uv_pipe_t*) handle);
+ break;
+
+ case UV_TTY:
+ uv_tty_endgame(loop, (uv_tty_t*) handle);
+ break;
+
+ case UV_UDP:
+ uv_udp_endgame(loop, (uv_udp_t*) handle);
+ break;
+
+ case UV_POLL:
+ uv_poll_endgame(loop, (uv_poll_t*) handle);
+ break;
+
+ case UV_TIMER:
+ uv_timer_endgame(loop, (uv_timer_t*) handle);
+ break;
+
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ uv_loop_watcher_endgame(loop, handle);
+ break;
+
+ case UV_ASYNC:
+ uv_async_endgame(loop, (uv_async_t*) handle);
+ break;
+
+ case UV_PROCESS:
+ uv_process_endgame(loop, (uv_process_t*) handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+#endif /* UV_WIN_HANDLE_INL_H_ */
diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c
index a3abb0ab8..9343d256e 100644
--- a/deps/uv/src/win/handle.c
+++ b/deps/uv/src/win/handle.c
@@ -24,6 +24,7 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
uv_handle_type uv_guess_handle(uv_file file) {
@@ -62,15 +63,6 @@ int uv_is_active(const uv_handle_t* handle) {
}
-void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) {
- handle->loop = loop;
- handle->flags = UV__HANDLE_REF;
- ngx_queue_insert_tail(&loop->handle_queue, &handle->handle_queue);
-
- loop->counters.handle_init++;
-}
-
-
void uv_close(uv_handle_t* handle, uv_close_cb cb) {
uv_loop_t* loop = handle->loop;
@@ -150,73 +142,3 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
int uv_is_closing(const uv_handle_t* handle) {
return handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED);
}
-
-
-void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
- if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
- handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
-
- handle->endgame_next = loop->endgame_handles;
- loop->endgame_handles = handle;
- }
-}
-
-
-void uv_process_endgames(uv_loop_t* loop) {
- uv_handle_t* handle;
-
- while (loop->endgame_handles) {
- handle = loop->endgame_handles;
- loop->endgame_handles = handle->endgame_next;
-
- handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
-
- switch (handle->type) {
- case UV_TCP:
- uv_tcp_endgame(loop, (uv_tcp_t*) handle);
- break;
-
- case UV_NAMED_PIPE:
- uv_pipe_endgame(loop, (uv_pipe_t*) handle);
- break;
-
- case UV_TTY:
- uv_tty_endgame(loop, (uv_tty_t*) handle);
- break;
-
- case UV_UDP:
- uv_udp_endgame(loop, (uv_udp_t*) handle);
- break;
-
- case UV_POLL:
- uv_poll_endgame(loop, (uv_poll_t*) handle);
- break;
-
- case UV_TIMER:
- uv_timer_endgame(loop, (uv_timer_t*) handle);
- break;
-
- case UV_PREPARE:
- case UV_CHECK:
- case UV_IDLE:
- uv_loop_watcher_endgame(loop, handle);
- break;
-
- case UV_ASYNC:
- uv_async_endgame(loop, (uv_async_t*) handle);
- break;
-
- case UV_PROCESS:
- uv_process_endgame(loop, (uv_process_t*) handle);
- break;
-
- case UV_FS_EVENT:
- uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
- break;
-
- default:
- assert(0);
- break;
- }
- }
-}
diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h
index 787622614..f5d0d1721 100644
--- a/deps/uv/src/win/internal.h
+++ b/deps/uv/src/win/internal.h
@@ -32,6 +32,7 @@
/*
* Handles
+ * (also see handle-inl.h)
*/
/* Used by all handles. */
@@ -81,96 +82,14 @@
#define UV_HANDLE_POLL_SLOW 0x02000000
-void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
-void uv_process_endgames(uv_loop_t* loop);
-
-#define DECREASE_PENDING_REQ_COUNT(handle) \
- do { \
- assert(handle->reqs_pending > 0); \
- handle->reqs_pending--; \
- \
- if (handle->flags & UV_HANDLE_CLOSING && \
- handle->reqs_pending == 0) { \
- uv_want_endgame(loop, (uv_handle_t*)handle); \
- } \
- } while (0)
-
-#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
- ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
-
-#define UV_SUCCEEDED_WITH_IOCP(result) \
- ((result) || (GetLastError() == ERROR_IO_PENDING))
-
-#define DECREASE_ACTIVE_COUNT(loop, handle) \
- do { \
- if (--(handle)->activecnt == 0 && \
- !((handle)->flags & UV_HANDLE_CLOSING)) { \
- uv__handle_stop((handle)); \
- } \
- assert((handle)->activecnt >= 0); \
- } while (0)
-
-#define INCREASE_ACTIVE_COUNT(loop, handle) \
- do { \
- if ((handle)->activecnt++ == 0) { \
- uv__handle_start((handle)); \
- } \
- assert((handle)->activecnt > 0); \
- } while (0)
-
-#define REGISTER_HANDLE_REQ(loop, handle, req) \
- do { \
- INCREASE_ACTIVE_COUNT((loop), (handle)); \
- uv__req_register((loop), (req)); \
- } while (0)
-
-#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
- do { \
- DECREASE_ACTIVE_COUNT((loop), (handle)); \
- 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
+ * Requests: see req-inl.h
*/
-void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle);
/*
- * Requests
+ * Streams: see stream-inl.h
*/
-void uv_req_init(uv_loop_t* loop, uv_req_t* req);
-
-uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped);
-
-void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req);
-void uv_process_reqs(uv_loop_t* loop);
-
-#define POST_COMPLETION_FOR_REQ(loop, req) \
- if (!PostQueuedCompletionStatus((loop)->iocp, \
- 0, \
- 0, \
- &((req)->overlapped))) { \
- uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
- }
-
-
-/*
- * Streams
- */
-void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle);
-void uv_connection_init(uv_stream_t* handle);
-
-size_t uv_count_bufs(uv_buf_t bufs[], int count);
/*
@@ -299,6 +218,8 @@ void uv_prepare_invoke(uv_loop_t* loop);
void uv_check_invoke(uv_loop_t* loop);
void uv_idle_invoke(uv_loop_t* loop);
+void uv__once_init();
+
/*
* Async watcher
@@ -347,33 +268,16 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
-/* Utils */
+/*
+ * Utilities.
+ */
+void uv__util_init();
+
int uv_parent_pid();
void uv_filetime_to_time_t(FILETIME* file_time, time_t* stat_time);
void uv_fatal_error(const int errorno, const char* syscall);
uv_err_code uv_translate_sys_error(int sys_errno);
-#define SET_REQ_STATUS(req, status) \
- (req)->overlapped.Internal = (ULONG_PTR) (status)
-
-#define SET_REQ_ERROR(req, error) \
- SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
-
-#define SET_REQ_SUCCESS(req) \
- SET_REQ_STATUS((req), STATUS_SUCCESS)
-
-#define GET_REQ_STATUS(req) \
- ((req)->overlapped.Internal)
-
-#define REQ_SUCCESS(req) \
- (NT_SUCCESS(GET_REQ_STATUS((req))))
-
-#define GET_REQ_ERROR(req) \
- (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
-
-#define GET_REQ_SOCK_ERROR(req) \
- (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
-
/*
* Winapi and ntapi utility functions
diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c
index c573cd7d6..a753a0632 100644
--- a/deps/uv/src/win/loop-watcher.c
+++ b/deps/uv/src/win/loop-watcher.c
@@ -23,6 +23,7 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
index 8a64f71bf..055104712 100644
--- a/deps/uv/src/win/pipe.c
+++ b/deps/uv/src/win/pipe.c
@@ -26,6 +26,9 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
/* A zero-size buffer for use by uv_pipe_read */
diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c
index 55e0b27e8..ba31ae9ef 100644
--- a/deps/uv/src/win/poll.c
+++ b/deps/uv/src/win/poll.c
@@ -19,12 +19,13 @@
* IN THE SOFTWARE.
*/
+#include <assert.h>
+#include <io.h>
#include "uv.h"
#include "internal.h"
-
-#include <assert.h>
-#include <io.h>
+#include "handle-inl.h"
+#include "req-inl.h"
static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
@@ -42,6 +43,28 @@ typedef struct uv_single_fd_set_s {
} uv_single_fd_set_t;
+static OVERLAPPED overlapped_dummy_;
+static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
+
+
+static void uv__init_overlapped_dummy(void) {
+ HANDLE event;
+
+ event = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (event == NULL)
+ uv_fatal_error(GetLastError(), "CreateEvent");
+
+ memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
+ overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
+}
+
+
+static OVERLAPPED* uv__get_overlapped_dummy() {
+ uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
+ return &overlapped_dummy_;
+}
+
+
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
AFD_POLL_INFO* afd_poll_info;
@@ -97,43 +120,26 @@ static void uv__fast_poll_submit_poll_req(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;
- OVERLAPPED overlapped;
-
- event = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (event == NULL) {
- uv__set_sys_error(loop, GetLastError());
- return -1;
- }
- afd_poll_info.Exclusive = FALSE;
+ afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
- afd_poll_info.Timeout.QuadPart = 0;
+ afd_poll_info.Timeout.QuadPart = INT64_MAX;
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);
-
result = uv_msafd_poll(handle->socket,
&afd_poll_info,
- &overlapped);
+ uv__get_overlapped_dummy());
if (result == SOCKET_ERROR) {
DWORD error = WSAGetLastError();
if (error != WSA_IO_PENDING) {
uv__set_sys_error(loop, WSAGetLastError());
- CloseHandle(event);
return -1;
}
}
- if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) {
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
- }
-
- CloseHandle(event);
return 0;
}
@@ -181,6 +187,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
/* Stop polling. */
handle->events = 0;
+ uv__handle_stop(handle);
}
if (events != 0) {
@@ -229,17 +236,9 @@ static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
} else {
- /* Try to cancel outstanding poll requests. */
- if (pCancelIoEx) {
- /* Use CancelIoEx to cancel poll requests if available. */
- if (handle->submitted_events_1)
- pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_1.overlapped);
- if (handle->submitted_events_2)
- 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_req(loop, handle);
- }
+ /* Cancel outstanding poll requests by executing another, unique poll */
+ /* request that forces the outstanding ones to return. */
+ uv__fast_poll_cancel_poll_req(loop, handle);
}
}
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 23a3012e1..332ef0f58 100644
--- a/deps/uv/src/win/process.c
+++ b/deps/uv/src/win/process.c
@@ -19,15 +19,16 @@
* IN THE SOFTWARE.
*/
-#include "uv.h"
-#include "internal.h"
-
#include <assert.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
-#include <windows.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
#define SIGKILL 9
@@ -86,7 +87,7 @@ typedef struct env_var {
((LPBYTE) (buffer))
#define CHILD_STDIO_CBRESERVED2(buffer) \
- CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)))
+ ((WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))))
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
*((unsigned char*) (buffer) + sizeof(int) + fd)
@@ -756,6 +757,32 @@ static int duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
}
+static int create_nul_handle(uv_loop_t* loop, HANDLE* handle_ptr,
+ DWORD access) {
+ HANDLE handle;
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ handle = CreateFileW(L"NUL",
+ access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ uv__set_sys_error(loop, GetLastError());
+ return -1;
+ }
+
+ *handle_ptr = handle;
+ return 0;
+}
+
+
static void set_child_stdio_noinherit(void* buffer) {
int i, count;
@@ -965,16 +992,34 @@ static int init_child_stdio(uv_loop_t* loop, uv_process_options_t* options,
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
}
- for (i = 0; i < options->stdio_count; i++) {
- uv_stdio_container_t fdopt = options->stdio[i];
+ for (i = 0; i < count; i++) {
+ uv_stdio_container_t fdopt;
+ if (i < options->stdio_count) {
+ fdopt = options->stdio[i];
+ } else {
+ fdopt.flags = UV_IGNORE;
+ }
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;
+ /* Starting a process with no stdin/stout/stderr can confuse it. */
+ /* So no matter what the user specified, we make sure the first */
+ /* three FDs are always open in their typical modes, e.g. stdin */
+ /* be readable and stdout/err should be writable. For FDs > 2, don't */
+ /* do anything - all handles in the stdio buffer are initialized with */
+ /* INVALID_HANDLE_VALUE, which should be okay. */
+ if (i <= 2) {
+ DWORD access = (i == 0) ? FILE_GENERIC_READ :
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ if (create_nul_handle(loop,
+ &CHILD_STDIO_HANDLE(buffer, i),
+ access) < 0) {
+ goto error;
+ }
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ }
+ break;
case UV_CREATE_PIPE: {
/* Create a pair of two connected pipe ends; one end is turned into */
@@ -1077,6 +1122,7 @@ static int init_child_stdio(uv_loop_t* loop, uv_process_options_t* options,
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
+ break;
}
default:
diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h
new file mode 100644
index 000000000..a0d91cb19
--- /dev/null
+++ b/deps/uv/src/win/req-inl.h
@@ -0,0 +1,225 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_REQ_INL_H_
+#define UV_WIN_REQ_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define SET_REQ_STATUS(req, status) \
+ (req)->overlapped.Internal = (ULONG_PTR) (status)
+
+#define SET_REQ_ERROR(req, error) \
+ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
+
+#define SET_REQ_SUCCESS(req) \
+ SET_REQ_STATUS((req), STATUS_SUCCESS)
+
+#define GET_REQ_STATUS(req) \
+ ((NTSTATUS) (req)->overlapped.Internal)
+
+#define REQ_SUCCESS(req) \
+ (NT_SUCCESS(GET_REQ_STATUS((req))))
+
+#define GET_REQ_ERROR(req) \
+ (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
+
+#define GET_REQ_SOCK_ERROR(req) \
+ (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+
+
+#define REGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ INCREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_register((loop), (req)); \
+ } while (0)
+
+#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ DECREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_unregister((loop), (req)); \
+ } while (0)
+
+
+#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
+ ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
+
+#define UV_SUCCEEDED_WITH_IOCP(result) \
+ ((result) || (GetLastError() == ERROR_IO_PENDING))
+
+
+#define POST_COMPLETION_FOR_REQ(loop, req) \
+ if (!PostQueuedCompletionStatus((loop)->iocp, \
+ 0, \
+ 0, \
+ &((req)->overlapped))) { \
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
+ }
+
+
+INLINE static void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
+ loop->counters.req_init++;
+ req->type = UV_UNKNOWN_REQ;
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+ return CONTAINING_RECORD(overlapped, uv_req_t, overlapped);
+}
+
+
+INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
+ req->next_req = NULL;
+ if (loop->pending_reqs_tail) {
+ req->next_req = loop->pending_reqs_tail->next_req;
+ loop->pending_reqs_tail->next_req = req;
+ loop->pending_reqs_tail = req;
+ } else {
+ req->next_req = req;
+ loop->pending_reqs_tail = req;
+ }
+}
+
+
+#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
+ do { \
+ switch (((uv_handle_t*) (req)->handle_at)->type) { \
+ case UV_TCP: \
+ uv_process_tcp_##method##_req(loop, \
+ (uv_tcp_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_NAMED_PIPE: \
+ uv_process_pipe_##method##_req(loop, \
+ (uv_pipe_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_TTY: \
+ uv_process_tty_##method##_req(loop, \
+ (uv_tty_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ default: \
+ assert(0); \
+ } \
+ } while (0)
+
+
+INLINE static void uv_process_reqs(uv_loop_t* loop) {
+ uv_req_t* req;
+ uv_req_t* first;
+ uv_req_t* next;
+
+ if (loop->pending_reqs_tail == NULL) {
+ return;
+ }
+
+ first = loop->pending_reqs_tail->next_req;
+ next = first;
+ loop->pending_reqs_tail = NULL;
+
+ while (next != NULL) {
+ req = next;
+ next = req->next_req != first ? req->next_req : NULL;
+
+ switch (req->type) {
+ case UV_READ:
+ DELEGATE_STREAM_REQ(loop, req, read, data);
+ break;
+
+ case UV_WRITE:
+ DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
+ break;
+
+ case UV_ACCEPT:
+ DELEGATE_STREAM_REQ(loop, req, accept, data);
+ break;
+
+ case UV_CONNECT:
+ DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
+ break;
+
+ case UV_SHUTDOWN:
+ /* Tcp shutdown requests don't come here. */
+ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
+ uv_process_pipe_shutdown_req(
+ loop,
+ (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
+ (uv_shutdown_t*) req);
+ break;
+
+ case UV_UDP_RECV:
+ uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
+ break;
+
+ case UV_UDP_SEND:
+ uv_process_udp_send_req(loop,
+ ((uv_udp_send_t*) req)->handle,
+ (uv_udp_send_t*) req);
+ break;
+
+ case UV_WAKEUP:
+ uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
+ break;
+
+ case UV_POLL_REQ:
+ uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+ break;
+
+ case UV_GETADDRINFO:
+ uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
+ break;
+
+ case UV_PROCESS_EXIT:
+ uv_process_proc_exit(loop, (uv_process_t*) req->data);
+ break;
+
+ case UV_PROCESS_CLOSE:
+ uv_process_proc_close(loop, (uv_process_t*) req->data);
+ break;
+
+ case UV_FS:
+ uv_process_fs_req(loop, (uv_fs_t*) req);
+ break;
+
+ case UV_WORK:
+ uv_process_work_req(loop, (uv_work_t*) req);
+ break;
+
+ case UV_FS_EVENT_REQ:
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+}
+
+#endif /* UV_WIN_REQ_INL_H_ */
diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c
index ada4eb1ba..111cc5e28 100644
--- a/deps/uv/src/win/req.c
+++ b/deps/uv/src/win/req.c
@@ -23,147 +23,3 @@
#include "uv.h"
#include "internal.h"
-
-
-void uv_req_init(uv_loop_t* loop, uv_req_t* req) {
- loop->counters.req_init++;
- req->type = UV_UNKNOWN_REQ;
- SET_REQ_SUCCESS(req);
-}
-
-
-uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
- return CONTAINING_RECORD(overlapped, uv_req_t, overlapped);
-}
-
-
-void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
- req->next_req = NULL;
- if (loop->pending_reqs_tail) {
- req->next_req = loop->pending_reqs_tail->next_req;
- loop->pending_reqs_tail->next_req = req;
- loop->pending_reqs_tail = req;
- } else {
- req->next_req = req;
- loop->pending_reqs_tail = req;
- }
-}
-
-
-#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
- do { \
- switch (((uv_handle_t*) (req)->handle_at)->type) { \
- case UV_TCP: \
- uv_process_tcp_##method##_req(loop, \
- (uv_tcp_t*) ((req)->handle_at), \
- req); \
- break; \
- \
- case UV_NAMED_PIPE: \
- uv_process_pipe_##method##_req(loop, \
- (uv_pipe_t*) ((req)->handle_at), \
- req); \
- break; \
- \
- case UV_TTY: \
- uv_process_tty_##method##_req(loop, \
- (uv_tty_t*) ((req)->handle_at), \
- req); \
- break; \
- \
- default: \
- assert(0); \
- } \
- } while (0)
-
-
-void uv_process_reqs(uv_loop_t* loop) {
- uv_req_t* req;
- uv_req_t* first;
- uv_req_t* next;
-
- if (loop->pending_reqs_tail == NULL) {
- return;
- }
-
- first = loop->pending_reqs_tail->next_req;
- next = first;
- loop->pending_reqs_tail = NULL;
-
- while (next != NULL) {
- req = next;
- next = req->next_req != first ? req->next_req : NULL;
-
- switch (req->type) {
- case UV_READ:
- DELEGATE_STREAM_REQ(loop, req, read, data);
- break;
-
- case UV_WRITE:
- DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
- break;
-
- case UV_ACCEPT:
- DELEGATE_STREAM_REQ(loop, req, accept, data);
- break;
-
- case UV_CONNECT:
- DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
- break;
-
- case UV_SHUTDOWN:
- /* Tcp shutdown requests don't come here. */
- assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
- uv_process_pipe_shutdown_req(
- loop,
- (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
- (uv_shutdown_t*) req);
- break;
-
- case UV_UDP_RECV:
- uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
- break;
-
- case UV_UDP_SEND:
- uv_process_udp_send_req(loop,
- ((uv_udp_send_t*) req)->handle,
- (uv_udp_send_t*) req);
- break;
-
- case UV_WAKEUP:
- uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
- break;
-
- case UV_POLL_REQ:
- uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
- break;
-
- case UV_GETADDRINFO:
- uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
- break;
-
- case UV_PROCESS_EXIT:
- uv_process_proc_exit(loop, (uv_process_t*) req->data);
- break;
-
- case UV_PROCESS_CLOSE:
- uv_process_proc_close(loop, (uv_process_t*) req->data);
- break;
-
- case UV_FS:
- uv_process_fs_req(loop, (uv_fs_t*) req);
- break;
-
- case UV_WORK:
- uv_process_work_req(loop, (uv_work_t*) req);
- break;
-
- case UV_FS_EVENT_REQ:
- uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
- break;
-
- default:
- assert(0);
- }
- }
-}
diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h
new file mode 100644
index 000000000..91313566a
--- /dev/null
+++ b/deps/uv/src/win/stream-inl.h
@@ -0,0 +1,67 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_STREAM_INL_H_
+#define UV_WIN_STREAM_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+INLINE static void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) {
+ uv_handle_init(loop, (uv_handle_t*) handle);
+ handle->write_queue_size = 0;
+ handle->activecnt = 0;
+
+ loop->counters.stream_init++;
+}
+
+
+INLINE static void uv_connection_init(uv_stream_t* handle) {
+ handle->flags |= UV_HANDLE_CONNECTION;
+ handle->write_reqs_pending = 0;
+
+ uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
+ handle->read_req.event_handle = NULL;
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ handle->read_req.type = UV_READ;
+ handle->read_req.data = handle;
+
+ handle->shutdown_req = NULL;
+}
+
+
+INLINE static size_t uv_count_bufs(uv_buf_t bufs[], int count) {
+ size_t bytes = 0;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ bytes += (size_t)bufs[i].len;
+ }
+
+ return bytes;
+}
+
+#endif /* UV_WIN_STREAM_INL_H_ */
diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c
index dad8669b1..195e0b801 100644
--- a/deps/uv/src/win/stream.c
+++ b/deps/uv/src/win/stream.c
@@ -23,29 +23,8 @@
#include "uv.h"
#include "internal.h"
-
-
-void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) {
- uv_handle_init(loop, (uv_handle_t*) handle);
- handle->write_queue_size = 0;
- handle->activecnt = 0;
-
- loop->counters.stream_init++;
-}
-
-
-void uv_connection_init(uv_stream_t* handle) {
- handle->flags |= UV_HANDLE_CONNECTION;
- handle->write_reqs_pending = 0;
-
- uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
- handle->read_req.event_handle = NULL;
- handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
- handle->read_req.type = UV_READ;
- handle->read_req.data = handle;
-
- handle->shutdown_req = NULL;
-}
+#include "handle-inl.h"
+#include "req-inl.h"
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
@@ -178,18 +157,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
}
-size_t uv_count_bufs(uv_buf_t bufs[], int count) {
- size_t bytes = 0;
- int i;
-
- for (i = 0; i < count; i++) {
- bytes += (size_t)bufs[i].len;
- }
-
- return bytes;
-}
-
-
int uv_is_readable(const uv_stream_t* handle) {
return !(handle->flags & UV_HANDLE_EOF);
}
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
index c049d64d4..6ea39a2b0 100644
--- a/deps/uv/src/win/tcp.c
+++ b/deps/uv/src/win/tcp.c
@@ -23,6 +23,10 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
/*
diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c
index 01b814088..aecfaf4f8 100644
--- a/deps/uv/src/win/thread.c
+++ b/deps/uv/src/win/thread.c
@@ -20,6 +20,7 @@
*/
#include <assert.h>
+#include <limits.h>
#include "uv.h"
#include "internal.h"
@@ -207,6 +208,44 @@ void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
}
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
+ return *sem ? 0 : -1;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (!CloseHandle(*sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (!ReleaseSemaphore(*sem, 1, NULL))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ DWORD r = WaitForSingleObject(*sem, 0);
+
+ if (r == WAIT_OBJECT_0)
+ return 0;
+
+ if (r == WAIT_TIMEOUT)
+ return -1;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) {
pInitializeSRWLock(&rwlock->srwlock_);
return 0;
diff --git a/deps/uv/src/win/threadpool.c b/deps/uv/src/win/threadpool.c
index e066810d5..48e00b879 100644
--- a/deps/uv/src/win/threadpool.c
+++ b/deps/uv/src/win/threadpool.c
@@ -23,6 +23,7 @@
#include "uv.h"
#include "internal.h"
+#include "req-inl.h"
static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req,
diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c
index e71e4c658..69638bc9c 100644
--- a/deps/uv/src/win/timer.c
+++ b/deps/uv/src/win/timer.c
@@ -25,15 +25,7 @@
#include "uv.h"
#include "internal.h"
#include "tree.h"
-
-
-#undef NANOSEC
-#define NANOSEC 1000000000
-
-
-/* The resolution of the high-resolution clock. */
-static uint64_t uv_hrtime_frequency_ = 0;
-static uv_once_t uv_hrtime_init_guard_ = UV_ONCE_INIT;
+#include "handle-inl.h"
void uv_update_time(uv_loop_t* loop) {
@@ -58,43 +50,6 @@ int64_t uv_now(uv_loop_t* loop) {
}
-static void uv_hrtime_init(void) {
- LARGE_INTEGER frequency;
-
- if (!QueryPerformanceFrequency(&frequency)) {
- uv_hrtime_frequency_ = 0;
- return;
- }
-
- uv_hrtime_frequency_ = frequency.QuadPart;
-}
-
-
-uint64_t uv_hrtime(void) {
- LARGE_INTEGER counter;
-
- uv_once(&uv_hrtime_init_guard_, uv_hrtime_init);
-
- /* If the performance frequency is zero, there's no support. */
- if (!uv_hrtime_frequency_) {
- /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */
- return 0;
- }
-
- if (!QueryPerformanceCounter(&counter)) {
- /* uv__set_sys_error(loop, GetLastError()); */
- return 0;
- }
-
- /* Because we have no guarantee about the order of magnitude of the */
- /* performance counter frequency, and there may not be much headroom to */
- /* multiply by NANOSEC without overflowing, we use 128-bit math instead. */
- return ((uint64_t) counter.LowPart * NANOSEC / uv_hrtime_frequency_) +
- (((uint64_t) counter.HighPart * NANOSEC / uv_hrtime_frequency_)
- << 32);
-}
-
-
static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
if (a->due < b->due)
return -1;
diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c
index 07159922b..047cad26f 100644
--- a/deps/uv/src/win/tty.c
+++ b/deps/uv/src/win/tty.c
@@ -26,6 +26,9 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
@@ -690,7 +693,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
if (!REQ_SUCCESS(req)) {
/* Read was not successful */
if ((handle->flags & UV_HANDLE_READING) &&
- !(handle->flags & UV_HANDLE_TTY_RAW)) {
+ handle->read_line_handle != NULL) {
/* Real error */
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c
index 3ea23f9d7..10cca00af 100644
--- a/deps/uv/src/win/udp.c
+++ b/deps/uv/src/win/udp.c
@@ -23,6 +23,9 @@
#include "uv.h"
#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
/*
diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c
index 10c227123..87a999ff5 100644
--- a/deps/uv/src/win/util.c
+++ b/deps/uv/src/win/util.c
@@ -47,11 +47,32 @@
*/
#define MAX_TITLE_LENGTH 8192
+/* The number of nanoseconds in one second. */
+#undef NANOSEC
+#define NANOSEC 1000000000
+
+/* Cached copy of the process title, plus a mutex guarding it. */
static char *process_title;
-static uv_once_t uv_process_title_init_guard_ = UV_ONCE_INIT;
static CRITICAL_SECTION process_title_lock;
+/* The tick frequency of the high-resolution clock. */
+static uint64_t hrtime_frequency_ = 0;
+
+
+/*
+ * One-time intialization code for functionality defined in util.c.
+ */
+void uv__util_init() {
+ /* Initialize process title access mutex. */
+ InitializeCriticalSection(&process_title_lock);
+
+ /* Retrieve high-resolution timer frequency. */
+ if (!QueryPerformanceFrequency((LARGE_INTEGER*) &hrtime_frequency_))
+ hrtime_frequency_ = 0;
+}
+
+
int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size,
char* utf8Buffer, size_t utf8Size) {
return WideCharToMultiByte(CP_UTF8,
@@ -76,90 +97,100 @@ int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer,
}
-int uv_exepath(char* buffer, size_t* size) {
- int retVal;
- size_t utf16Size;
- wchar_t* utf16Buffer;
+int uv_exepath(char* buffer, size_t* size_ptr) {
+ int utf8_len, utf16_buffer_len, utf16_len;
+ WCHAR* utf16_buffer;
- if (!buffer || !size) {
+ if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
return -1;
}
- utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * *size);
- if (!utf16Buffer) {
- retVal = -1;
- goto done;
+ if (*size_ptr > 32768) {
+ /* Windows paths can never be longer than this. */
+ utf16_buffer_len = 32768;
+ } else {
+ utf16_buffer_len = (int) *size_ptr;
}
- /* Get the path as UTF-16 */
- utf16Size = GetModuleFileNameW(NULL, utf16Buffer, *size - 1);
- if (utf16Size <= 0) {
- /* uv__set_sys_error(loop, GetLastError()); */
- retVal = -1;
- goto done;
+ utf16_buffer = (wchar_t*) malloc(sizeof(WCHAR) * utf16_buffer_len);
+ if (!utf16_buffer) {
+ return -1;
}
- utf16Buffer[utf16Size] = L'\0';
-
- /* Convert to UTF-8 */
- *size = uv_utf16_to_utf8(utf16Buffer, utf16Size, buffer, *size);
- if (!*size) {
- /* uv__set_sys_error(loop, GetLastError()); */
- retVal = -1;
- goto done;
+ /* Get the path as UTF-16. */
+ utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
+ if (utf16_len <= 0) {
+ goto error;
}
- buffer[*size] = '\0';
- retVal = 0;
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
-done:
- if (utf16Buffer) {
- free(utf16Buffer);
- }
+ /* Convert to UTF-8 */
+ utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr,
+ NULL,
+ NULL);
+ if (utf8_len == 0) {
+ goto error;
+ }
+
+ free(utf16_buffer);
+
+ /* utf8_len *does* include the terminating null at this point, but the */
+ /* returned size shouldn't. */
+ *size_ptr = utf8_len - 1;
+ return 0;
- return retVal;
+ error:
+ free(utf16_buffer);
+ return -1;
}
uv_err_t uv_cwd(char* buffer, size_t size) {
- uv_err_t err;
- size_t utf8Size;
- wchar_t* utf16Buffer = NULL;
-
- if (!buffer || !size) {
- err.code = UV_EINVAL;
- goto done;
- }
+ DWORD utf16_len;
+ WCHAR utf16_buffer[MAX_PATH + 1];
+ int r;
- utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * size);
- if (!utf16Buffer) {
- err.code = UV_ENOMEM;
- goto done;
+ if (buffer == NULL || size == 0) {
+ return uv__new_artificial_error(UV_EINVAL);
}
- if (!_wgetcwd(utf16Buffer, size - 1)) {
- err = uv__new_sys_error(_doserrno);
- goto done;
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv__new_sys_error(GetLastError());
}
- utf16Buffer[size - 1] = L'\0';
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
- /* Convert to UTF-8 */
- utf8Size = uv_utf16_to_utf8(utf16Buffer, -1, buffer, size);
- if (utf8Size == 0) {
- err = uv__new_sys_error(GetLastError());
- goto done;
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
}
- buffer[utf8Size] = '\0';
- err = uv_ok_;
-
-done:
- if (utf16Buffer) {
- free(utf16Buffer);
+ /* Convert to UTF-8 */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ size > INT_MAX ? INT_MAX : (int) size,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv__new_sys_error(GetLastError());
}
- return err;
+ return uv_ok_;
}
@@ -266,17 +297,12 @@ char** uv_setup_args(int argc, char** argv) {
}
-static void uv_process_title_init(void) {
- InitializeCriticalSection(&process_title_lock);
-}
-
-
uv_err_t uv_set_process_title(const char* title) {
uv_err_t err;
int length;
wchar_t* title_w = NULL;
- uv_once(&uv_process_title_init_guard_, uv_process_title_init);
+ uv__once_init();
/* Find out how big the buffer for the wide-char title must be */
length = uv_utf8_to_utf16(title, NULL, 0);
@@ -351,7 +377,7 @@ static int uv__get_process_title() {
uv_err_t uv_get_process_title(char* buffer, size_t size) {
- uv_once(&uv_process_title_init_guard_, uv_process_title_init);
+ uv__once_init();
EnterCriticalSection(&process_title_lock);
/*
@@ -370,6 +396,31 @@ uv_err_t uv_get_process_title(char* buffer, size_t size) {
}
+uint64_t uv_hrtime(void) {
+ LARGE_INTEGER counter;
+
+ uv__once_init();
+
+ /* If the performance frequency is zero, there's no support. */
+ if (!hrtime_frequency_) {
+ /* uv__set_sys_error(loop, ERROR_NOT_SUPPORTED); */
+ return 0;
+ }
+
+ if (!QueryPerformanceCounter(&counter)) {
+ /* uv__set_sys_error(loop, GetLastError()); */
+ return 0;
+ }
+
+ /* Because we have no guarantee about the order of magnitude of the */
+ /* performance counter frequency, and there may not be much headroom to */
+ /* multiply by NANOSEC without overflowing, we use 128-bit math instead. */
+ return ((uint64_t) counter.LowPart * NANOSEC / hrtime_frequency_) +
+ (((uint64_t) counter.HighPart * NANOSEC / hrtime_frequency_)
+ << 32);
+}
+
+
uv_err_t uv_resident_set_memory(size_t* rss) {
HANDLE current_process;
PROCESS_MEMORY_COUNTERS pmc;
@@ -488,81 +539,148 @@ uv_err_t uv_uptime(double* uptime) {
uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- uv_err_t err;
- char key[128];
- HKEY processor_key = NULL;
- DWORD cpu_speed = 0;
- DWORD cpu_speed_length = sizeof(cpu_speed);
- char cpu_brand[256];
- DWORD cpu_brand_length = sizeof(cpu_brand);
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
+ DWORD sppi_size;
SYSTEM_INFO system_info;
+ DWORD cpu_count, i, r;
+ ULONG result_size;
+ size_t size;
+ uv_err_t err;
uv_cpu_info_t* cpu_info;
- unsigned int i;
- GetSystemInfo(&system_info);
+ *cpu_infos = NULL;
+ *count = 0;
- *cpu_infos = (uv_cpu_info_t*)malloc(system_info.dwNumberOfProcessors *
- sizeof(uv_cpu_info_t));
- if (!(*cpu_infos)) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
- }
+ uv__once_init();
- *count = 0;
+ GetSystemInfo(&system_info);
+ cpu_count = system_info.dwNumberOfProcessors;
- for (i = 0; i < system_info.dwNumberOfProcessors; i++) {
- _snprintf(key, sizeof(key), "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", i);
+ size = cpu_count * sizeof(uv_cpu_info_t);
+ *cpu_infos = (uv_cpu_info_t*) malloc(size);
+ if (*cpu_infos == NULL) {
+ err = uv__new_artificial_error(UV_ENOMEM);
+ goto out;
+ }
+ memset(*cpu_infos, 0, size);
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE,
- &processor_key) != ERROR_SUCCESS) {
- if (i == 0) {
- err = uv__new_sys_error(GetLastError());
- goto done;
- }
+ sppi_size = sizeof(*sppi) * cpu_count;
+ sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size);
+ if (!sppi) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
+ }
- continue;
+ r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ sppi,
+ sppi_size,
+ &result_size);
+ if (r != ERROR_SUCCESS || result_size != sppi_size) {
+ err = uv__new_sys_error(GetLastError());
+ goto out;
+ }
+
+ for (i = 0; i < cpu_count; i++) {
+ WCHAR key_name[128];
+ HKEY processor_key;
+ DWORD cpu_speed;
+ DWORD cpu_speed_size = sizeof(cpu_speed);
+ WCHAR cpu_brand[256];
+ DWORD cpu_brand_size = sizeof(cpu_brand);
+
+ _snwprintf(key_name,
+ ARRAY_SIZE(key_name),
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
+ i);
+
+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &processor_key);
+ if (r != ERROR_SUCCESS) {
+ err = uv__new_sys_error(GetLastError());
+ goto out;
}
- if (RegQueryValueEx(processor_key, "~MHz", NULL, NULL,
- (LPBYTE)&cpu_speed, &cpu_speed_length)
- != ERROR_SUCCESS) {
+ if (RegQueryValueExW(processor_key,
+ L"~MHz",
+ NULL, NULL,
+ (BYTE*) &cpu_speed,
+ &cpu_speed_size) != ERROR_SUCCESS) {
err = uv__new_sys_error(GetLastError());
- goto done;
+ RegCloseKey(processor_key);
+ goto out;
}
- if (RegQueryValueEx(processor_key, "ProcessorNameString", NULL, NULL,
- (LPBYTE)&cpu_brand, &cpu_brand_length)
- != ERROR_SUCCESS) {
+ if (RegQueryValueExW(processor_key,
+ L"ProcessorNameString",
+ NULL, NULL,
+ (BYTE*) &cpu_brand,
+ &cpu_brand_size) != ERROR_SUCCESS) {
err = uv__new_sys_error(GetLastError());
- goto done;
+ RegCloseKey(processor_key);
+ goto out;
}
RegCloseKey(processor_key);
- processor_key = NULL;
cpu_info = &(*cpu_infos)[i];
-
- /* $TODO: find times on windows */
- cpu_info->cpu_times.user = 0;
+ cpu_info->speed = cpu_speed;
+ cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
+ cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
+ sppi[i].IdleTime.QuadPart) / 10000;
+ cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
+ cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
cpu_info->cpu_times.nice = 0;
- cpu_info->cpu_times.sys = 0;
- cpu_info->cpu_times.idle = 0;
- cpu_info->cpu_times.irq = 0;
- cpu_info->model = strdup(cpu_brand);
- cpu_info->speed = cpu_speed;
+ size = uv_utf16_to_utf8(cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ NULL,
+ 0);
+ if (size == 0) {
+ err = uv__new_sys_error(GetLastError());
+ goto out;
+ }
+
+ /* Allocate 1 extra byte for the null terminator. */
+ cpu_info->model = (char*) malloc(size + 1);
+ if (cpu_info->model == NULL) {
+ err = uv__new_artificial_error(UV_ENOMEM);
+ goto out;
+ }
+
+ if (uv_utf16_to_utf8(cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ cpu_info->model,
+ size) == 0) {
+ err = uv__new_sys_error(GetLastError());
+ goto out;
+ }
+
+ /* Ensure that cpu_info->model is null terminated. */
+ cpu_info->model[size] = '\0';
(*count)++;
}
err = uv_ok_;
-done:
- if (processor_key) {
- RegCloseKey(processor_key);
+ out:
+ if (sppi) {
+ free(sppi);
}
- if (err.code != UV_OK) {
+ if (err.code != UV_OK &&
+ *cpu_infos != NULL) {
+ int i;
+
+ for (i = 0; i < *count; i++) {
+ /* This is safe because the cpu_infos memory area is zeroed out */
+ /* immediately after allocating it. */
+ free((*cpu_infos)[i].model);
+ }
free(*cpu_infos);
+
*cpu_infos = NULL;
*count = 0;
}
diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c
index 4614a3ada..80c3e521c 100644
--- a/deps/uv/src/win/winapi.c
+++ b/deps/uv/src/win/winapi.c
@@ -29,6 +29,7 @@ sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtDeviceIoControlFile pNtDeviceIoControlFile;
sNtQueryInformationFile pNtQueryInformationFile;
sNtSetInformationFile pNtSetInformationFile;
+sNtQuerySystemInformation pNtQuerySystemInformation;
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
sCreateSymbolicLinkW pCreateSymbolicLinkW;
@@ -79,6 +80,13 @@ void uv_winapi_init() {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
+ pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
+ ntdll_module,
+ "NtQuerySystemInformation");
+ if (pNtQuerySystemInformation == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
kernel32_module = GetModuleHandleA("kernel32.dll");
if (kernel32_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h
index 4b1a249fb..2f57e39ba 100644
--- a/deps/uv/src/win/winapi.h
+++ b/deps/uv/src/win/winapi.h
@@ -28,11 +28,6 @@
/*
* Ntdll headers
*/
-#ifndef _NTDEF_
- typedef LONG NTSTATUS;
- typedef NTSTATUS *PNTSTATUS;
-#endif
-
#ifndef STATUS_SEVERITY_SUCCESS
# define STATUS_SEVERITY_SUCCESS 0x0
#endif
@@ -4207,6 +4202,19 @@ typedef enum _FILE_INFORMATION_CLASS {
FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER DpcTime;
+ LARGE_INTEGER InterruptTime;
+ ULONG InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+#ifndef SystemProcessorPerformanceInformation
+# define SystemProcessorPerformanceInformation 8
+#endif
+
#ifndef DEVICE_TYPE
# define DEVICE_TYPE DWORD
#endif
@@ -4323,6 +4331,12 @@ typedef NTSTATUS (NTAPI *sNtSetInformationFile)
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass);
+typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
+ (UINT SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength);
+
/*
* Kernel32 headers
@@ -4410,6 +4424,7 @@ extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
extern sNtQueryInformationFile pNtQueryInformationFile;
extern sNtSetInformationFile pNtSetInformationFile;
+extern sNtQuerySystemInformation pNtQuerySystemInformation;
/* Kernel32 function pointers */
diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c
index 37f91da47..fb1630375 100644
--- a/deps/uv/test/run-tests.c
+++ b/deps/uv/test/run-tests.c
@@ -24,6 +24,8 @@
#ifdef _WIN32
# include <io.h>
+#else
+# include <unistd.h>
#endif
#include "uv.h"
@@ -120,5 +122,17 @@ static int maybe_run_test(int argc, char **argv) {
return 1;
}
+ if (strcmp(argv[1], "spawn_helper6") == 0) {
+ int r;
+
+ r = fprintf(stdout, "hello world\n");
+ ASSERT(r > 0);
+
+ r = fprintf(stderr, "hello errworld\n");
+ ASSERT(r > 0);
+
+ return 1;
+ }
+
return run_test(argv[1], TEST_TIMEOUT, 0);
}
diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h
index 9a5ba695a..b9104d6f8 100644
--- a/deps/uv/test/test-list.h
+++ b/deps/uv/test/test-list.h
@@ -22,6 +22,9 @@
TEST_DECLARE (platform_output)
TEST_DECLARE (callback_order)
TEST_DECLARE (run_once)
+TEST_DECLARE (semaphore_1)
+TEST_DECLARE (semaphore_2)
+TEST_DECLARE (semaphore_3)
TEST_DECLARE (tty)
TEST_DECLARE (stdio_over_pipes)
TEST_DECLARE (ipc_listen_before_write)
@@ -37,6 +40,8 @@ TEST_DECLARE (pipe_ping_pong)
TEST_DECLARE (delayed_accept)
TEST_DECLARE (multiple_listen)
TEST_DECLARE (tcp_writealot)
+TEST_DECLARE (tcp_connect_error_after_write)
+TEST_DECLARE (tcp_shutdown_after_write)
TEST_DECLARE (tcp_bind_error_addrinuse)
TEST_DECLARE (tcp_bind_error_addrnotavail_1)
TEST_DECLARE (tcp_bind_error_addrnotavail_2)
@@ -120,6 +125,7 @@ TEST_DECLARE (spawn_exit_code)
TEST_DECLARE (spawn_stdout)
TEST_DECLARE (spawn_stdin)
TEST_DECLARE (spawn_stdio_greater_than_3)
+TEST_DECLARE (spawn_ignored_stdio)
TEST_DECLARE (spawn_and_kill)
TEST_DECLARE (spawn_detached)
TEST_DECLARE (spawn_and_kill_with_std)
@@ -168,6 +174,7 @@ TEST_DECLARE (counters_init)
TEST_DECLARE (dlerror)
TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
+TEST_DECLARE (poll_close)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
@@ -191,6 +198,9 @@ TASK_LIST_START
TEST_ENTRY (callback_order)
#endif
TEST_ENTRY (run_once)
+ TEST_ENTRY (semaphore_1)
+ TEST_ENTRY (semaphore_2)
+ TEST_ENTRY (semaphore_3)
TEST_ENTRY (pipe_connect_bad_name)
TEST_ENTRY (pipe_connect_to_file)
@@ -220,6 +230,10 @@ TASK_LIST_START
TEST_ENTRY (tcp_writealot)
TEST_HELPER (tcp_writealot, tcp4_echo_server)
+ TEST_ENTRY (tcp_shutdown_after_write)
+ TEST_HELPER (tcp_shutdown_after_write, tcp4_echo_server)
+
+ TEST_ENTRY (tcp_connect_error_after_write)
TEST_ENTRY (tcp_bind_error_addrinuse)
TEST_ENTRY (tcp_bind_error_addrnotavail_1)
TEST_ENTRY (tcp_bind_error_addrnotavail_2)
@@ -330,11 +344,13 @@ TASK_LIST_START
TEST_ENTRY (poll_duplex)
TEST_ENTRY (poll_unidirectional)
+ TEST_ENTRY (poll_close)
TEST_ENTRY (spawn_exit_code)
TEST_ENTRY (spawn_stdout)
TEST_ENTRY (spawn_stdin)
TEST_ENTRY (spawn_stdio_greater_than_3)
+ TEST_ENTRY (spawn_ignored_stdio)
TEST_ENTRY (spawn_and_kill)
TEST_ENTRY (spawn_detached)
TEST_ENTRY (spawn_and_kill_with_std)
diff --git a/deps/uv/test/test-poll-close.c b/deps/uv/test/test-poll-close.c
new file mode 100644
index 000000000..4c3701bc8
--- /dev/null
+++ b/deps/uv/test/test-poll-close.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 <errno.h>
+
+#ifndef _WIN32
+# include <fcntl.h>
+# include <sys/socket.h>
+# include <unistd.h>
+#endif
+
+#include "uv.h"
+#include "task.h"
+
+#define NUM_SOCKETS 64
+
+
+static int close_cb_called = 0;
+
+
+static void poll_cb_fail(uv_poll_t* handle, int status, int events) {
+ ASSERT(0 && "poll_fail_cb should never be called");
+}
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+TEST_IMPL(poll_close) {
+ uv_os_sock_t sockets[NUM_SOCKETS];
+ uv_poll_t poll_handles[NUM_SOCKETS];
+ int i;
+
+#ifdef _WIN32
+ {
+ struct WSAData wsa_data;
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+ }
+#endif
+
+ for (i = 0; i < NUM_SOCKETS; i++) {
+ sockets[i] = socket(AF_INET, SOCK_STREAM, 0);
+ uv_poll_init_socket(uv_default_loop(), &poll_handles[i], sockets[i]);
+ uv_poll_start(&poll_handles[i], UV_READABLE | UV_WRITABLE, NULL);
+ }
+
+ for (i = 0; i < NUM_SOCKETS; i++) {
+ uv_close((uv_handle_t*) &poll_handles[i], close_cb);
+ }
+
+ uv_run(uv_default_loop());
+
+ ASSERT(close_cb_called == NUM_SOCKETS);
+
+ return 0;
+}
diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c
index 0033f01f9..5a20b9d52 100644
--- a/deps/uv/test/test-poll.c
+++ b/deps/uv/test/test-poll.c
@@ -537,7 +537,7 @@ static void start_poll_test() {
#ifdef _WIN32
{
struct WSAData wsa_data;
- r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ int r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
ASSERT(r == 0);
}
#endif
@@ -550,10 +550,10 @@ static void start_poll_test() {
r = uv_run(uv_default_loop());
ASSERT(r == 0);
- /* Assert that at most one percent of the writable wakeups was spurious. */
+ /* Assert that at most five percent of the writable wakeups was spurious. */
ASSERT(spurious_writable_wakeups == 0 ||
(valid_writable_wakeups + spurious_writable_wakeups) /
- spurious_writable_wakeups > 100);
+ spurious_writable_wakeups > 20);
ASSERT(closed_connections == NUM_CLIENTS * 2);
}
diff --git a/deps/uv/test/test-semaphore.c b/deps/uv/test/test-semaphore.c
new file mode 100644
index 000000000..ee89d4fca
--- /dev/null
+++ b/deps/uv/test/test-semaphore.c
@@ -0,0 +1,111 @@
+/* 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 <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ uv_mutex_t mutex;
+ uv_sem_t sem;
+ int delay;
+ volatile int posted;
+} worker_config;
+
+
+static void worker(void* arg) {
+ worker_config* c = arg;
+
+ if (c->delay)
+ uv_sleep(c->delay);
+
+ uv_mutex_lock(&c->mutex);
+ ASSERT(c->posted == 0);
+ uv_sem_post(&c->sem);
+ c->posted = 1;
+ uv_mutex_unlock(&c->mutex);
+}
+
+
+TEST_IMPL(semaphore_1) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+
+ ASSERT(0 == uv_sem_init(&wc.sem, 0));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sleep(100);
+ uv_mutex_lock(&wc.mutex);
+ ASSERT(wc.posted == 1);
+ uv_sem_wait(&wc.sem); /* should not block */
+ uv_mutex_unlock(&wc.mutex); /* ergo, it should be ok to unlock after wait */
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_sem_destroy(&wc.sem);
+
+ return 0;
+}
+
+
+TEST_IMPL(semaphore_2) {
+ uv_thread_t thread;
+ worker_config wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.delay = 100;
+
+ ASSERT(0 == uv_sem_init(&wc.sem, 0));
+ ASSERT(0 == uv_mutex_init(&wc.mutex));
+ ASSERT(0 == uv_thread_create(&thread, worker, &wc));
+
+ uv_sem_wait(&wc.sem);
+
+ ASSERT(0 == uv_thread_join(&thread));
+ uv_mutex_destroy(&wc.mutex);
+ uv_sem_destroy(&wc.sem);
+
+ return 0;
+}
+
+
+TEST_IMPL(semaphore_3) {
+ uv_sem_t sem;
+
+ ASSERT(0 == uv_sem_init(&sem, 3));
+ uv_sem_wait(&sem); /* should not block */
+ uv_sem_wait(&sem); /* should not block */
+ ASSERT(0 == uv_sem_trywait(&sem));
+ ASSERT(-1 == uv_sem_trywait(&sem));
+
+ uv_sem_post(&sem);
+ ASSERT(0 == uv_sem_trywait(&sem));
+ ASSERT(-1 == uv_sem_trywait(&sem));
+
+ uv_sem_destroy(&sem);
+
+ return 0;
+}
diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c
index 604304380..51ed2e59d 100644
--- a/deps/uv/test/test-spawn.c
+++ b/deps/uv/test/test-spawn.c
@@ -329,6 +329,27 @@ TEST_IMPL(spawn_stdio_greater_than_3) {
}
+TEST_IMPL(spawn_ignored_stdio) {
+ int r;
+
+ init_process_options("spawn_helper6", exit_cb);
+
+ options.stdio = NULL;
+ options.stdio_count = 0;
+
+ 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);
+
+ return 0;
+}
+
+
TEST_IMPL(spawn_and_kill) {
int r;
diff --git a/deps/uv/test/test-tcp-connect-error-after-write.c b/deps/uv/test/test-tcp-connect-error-after-write.c
new file mode 100644
index 000000000..a9c020378
--- /dev/null
+++ b/deps/uv/test/test-tcp-connect-error-after-write.c
@@ -0,0 +1,95 @@
+/* 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>
+#include <string.h>
+
+static int connect_cb_called;
+static int write_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status == -1);
+ connect_cb_called++;
+ uv_close((uv_handle_t*)req->handle, close_cb);
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == -1);
+ write_cb_called++;
+}
+
+
+/*
+ * Try to connect to an address on which nothing listens, get ECONNREFUSED
+ * (uv errno 12) and get connect_cb() called once with status != 0.
+ * Related issue: https://github.com/joyent/libuv/issues/443
+ */
+TEST_IMPL(tcp_connect_error_after_write) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+ uv_write_t write_req;
+ uv_tcp_t conn;
+ uv_buf_t buf;
+ int r;
+
+#ifdef _WIN32
+ fprintf(stderr, "This test is disabled on Windows for now.\n");
+ fprintf(stderr, "See https://github.com/joyent/libuv/issues/444\n");
+ return 0; /* windows slackers... */
+#endif
+
+ addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+ buf = uv_buf_init("TEST", 4);
+
+ r = uv_tcp_init(uv_default_loop(), &conn);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == -1);
+ ASSERT(uv_last_error(uv_default_loop()).code == UV_EBADF);
+
+ r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(uv_default_loop());
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(close_cb_called == 1);
+
+ return 0;
+}
diff --git a/deps/uv/test/test-tcp-shutdown-after-write.c b/deps/uv/test/test-tcp-shutdown-after-write.c
new file mode 100644
index 000000000..8bf912361
--- /dev/null
+++ b/deps/uv/test/test-tcp-shutdown-after-write.c
@@ -0,0 +1,129 @@
+/* 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"
+
+static void write_cb(uv_write_t* req, int status);
+static void shutdown_cb(uv_shutdown_t* req, int status);
+
+static uv_tcp_t conn;
+static uv_timer_t timer;
+static uv_connect_t connect_req;
+static uv_write_t write_req;
+static uv_shutdown_t shutdown_req;
+
+static int connect_cb_called;
+static int write_cb_called;
+static int shutdown_cb_called;
+
+static int conn_close_cb_called;
+static int timer_close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ if (handle == (uv_handle_t*)&conn)
+ conn_close_cb_called++;
+ else if (handle == (uv_handle_t*)&timer)
+ timer_close_cb_called++;
+ else
+ ASSERT(0 && "bad handle in close_cb");
+}
+
+
+static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
+ static char slab[64];
+ return uv_buf_init(slab, sizeof(slab));
+}
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+ uv_buf_t buf;
+ int r;
+
+ uv_close((uv_handle_t*)handle, close_cb);
+
+ buf = uv_buf_init("TEST", 4);
+ r = uv_write(&write_req, (uv_stream_t*)&conn, &buf, 1, write_cb);
+ ASSERT(r == 0);
+
+ r = uv_shutdown(&shutdown_req, (uv_stream_t*)&conn, shutdown_cb);
+ ASSERT(r == 0);
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status == 0);
+ connect_cb_called++;
+}
+
+
+static void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
+}
+
+
+static void write_cb(uv_write_t* req, int status) {
+ ASSERT(status == 0);
+ write_cb_called++;
+}
+
+
+static void shutdown_cb(uv_shutdown_t* req, int status) {
+ ASSERT(status == 0);
+ shutdown_cb_called++;
+ uv_close((uv_handle_t*)&conn, close_cb);
+}
+
+
+TEST_IMPL(tcp_shutdown_after_write) {
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+ int r;
+
+ addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
+ loop = uv_default_loop();
+
+ r = uv_timer_init(loop, &timer);
+ ASSERT(r == 0);
+
+ r = uv_timer_start(&timer, timer_cb, 125, 0);
+ ASSERT(r == 0);
+
+ r = uv_tcp_init(loop, &conn);
+ ASSERT(r == 0);
+
+ r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb);
+ ASSERT(r == 0);
+
+ r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb);
+ ASSERT(r == 0);
+
+ r = uv_run(loop);
+ ASSERT(r == 0);
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(write_cb_called == 1);
+ ASSERT(shutdown_cb_called == 1);
+ ASSERT(conn_close_cb_called == 1);
+ ASSERT(timer_close_cb_called == 1);
+
+ return 0;
+}
diff --git a/deps/uv/test/test-tcp-writealot.c b/deps/uv/test/test-tcp-writealot.c
index 09c96f164..841df3c0d 100644
--- a/deps/uv/test/test-tcp-writealot.c
+++ b/deps/uv/test/test-tcp-writealot.c
@@ -37,9 +37,9 @@ static int shutdown_cb_called = 0;
static int connect_cb_called = 0;
static int write_cb_called = 0;
static int close_cb_called = 0;
-static int bytes_sent = 0;
-static int bytes_sent_done = 0;
-static int bytes_received_done = 0;
+static size_t bytes_sent = 0;
+static size_t bytes_sent_done = 0;
+static size_t bytes_received_done = 0;
static uv_connect_t connect_req;
static uv_shutdown_t shutdown_req;
diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp
index 47f876706..964933d51 100644
--- a/deps/uv/uv.gyp
+++ b/deps/uv/uv.gyp
@@ -142,6 +142,7 @@
'src/win/fs-event.c',
'src/win/getaddrinfo.c',
'src/win/handle.c',
+ 'src/win/handle-inl.h',
'src/win/internal.h',
'src/win/loop-watcher.c',
'src/win/pipe.c',
@@ -149,7 +150,9 @@
'src/win/poll.c',
'src/win/process.c',
'src/win/req.c',
+ 'src/win/req-inl.h',
'src/win/stream.c',
+ 'src/win/stream-inl.h',
'src/win/tcp.c',
'src/win/tty.c',
'src/win/threadpool.c',
@@ -327,9 +330,11 @@
'test/test-pipe-connect-error.c',
'test/test-platform-output.c',
'test/test-poll.c',
+ 'test/test-poll-close.c',
'test/test-process-title.c',
'test/test-ref.c',
'test/test-run-once.c',
+ 'test/test-semaphore.c',
'test/test-shutdown-close.c',
'test/test-shutdown-eof.c',
'test/test-spawn.c',
@@ -337,6 +342,8 @@
'test/test-tcp-bind-error.c',
'test/test-tcp-bind6-error.c',
'test/test-tcp-close.c',
+ 'test/test-tcp-connect-error-after-write.c',
+ 'test/test-tcp-shutdown-after-write.c',
'test/test-tcp-flags.c',
'test/test-tcp-connect-error.c',
'test/test-tcp-connect-timeout.c',