summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2012-09-13 16:18:54 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2012-09-13 16:18:54 +0200
commitdd1b9477063e39c5d916ebb602947340442d4d50 (patch)
tree01cc3cc477c26c8d529f7fd7db67aa8fcaccb974
parent2c97da82f5e23beb3f78258bb1340e63895e5125 (diff)
downloadnode-dd1b9477063e39c5d916ebb602947340442d4d50.tar.gz
deps: upgrade libuv to 1f9bd99
-rw-r--r--deps/uv/README.md3
-rw-r--r--deps/uv/config-unix.mk3
-rwxr-xr-xdeps/uv/gyp_uv8
-rw-r--r--deps/uv/include/uv-private/uv-darwin.h13
-rw-r--r--deps/uv/include/uv-private/uv-unix.h1
-rw-r--r--deps/uv/include/uv.h1
-rw-r--r--deps/uv/src/unix/async.c2
-rw-r--r--deps/uv/src/unix/core.c2
-rw-r--r--deps/uv/src/unix/darwin.c124
-rw-r--r--deps/uv/src/unix/fsevents.c225
-rw-r--r--deps/uv/src/unix/internal.h40
-rw-r--r--deps/uv/src/unix/kqueue.c25
-rw-r--r--deps/uv/src/unix/loop.c6
-rw-r--r--deps/uv/src/unix/netbsd.c244
-rw-r--r--deps/uv/src/unix/process.c4
-rw-r--r--deps/uv/src/unix/stream.c135
-rw-r--r--deps/uv/src/unix/tcp.c6
-rw-r--r--deps/uv/src/uv-common.c9
-rw-r--r--deps/uv/src/win/error.c1
-rw-r--r--deps/uv/src/win/internal.h5
-rw-r--r--deps/uv/src/win/pipe.c43
-rw-r--r--deps/uv/src/win/process-stdio.c3
-rw-r--r--deps/uv/src/win/stream.c51
-rw-r--r--deps/uv/src/win/tcp.c39
-rw-r--r--deps/uv/src/win/tty.c35
-rw-r--r--deps/uv/test/test-fs-event.c3
-rw-r--r--deps/uv/uv.gyp14
27 files changed, 896 insertions, 149 deletions
diff --git a/deps/uv/README.md b/deps/uv/README.md
index ca8fc2e3f..6789ffcb0 100644
--- a/deps/uv/README.md
+++ b/deps/uv/README.md
@@ -77,6 +77,9 @@ Macintosh users run
./gyp_uv -f xcode
xcodebuild -project uv.xcodeproj -configuration Release -target All
+Note for Linux users: compile your project with `-D_GNU_SOURCE` when you
+include `uv.h`. GYP builds take care of that automatically. If you use
+autotools, add a `AC_GNU_SOURCE` declaration to your `configure.ac`.
## Supported Platforms
diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk
index 53c636de1..c0be7e4a1 100644
--- a/deps/uv/config-unix.mk
+++ b/deps/uv/config-unix.mk
@@ -60,6 +60,7 @@ CPPFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
LINKFLAGS+=-framework CoreServices
OBJS += src/unix/darwin.o
OBJS += src/unix/kqueue.o
+OBJS += src/unix/fsevents.o
endif
ifeq (Linux,$(uname_S))
@@ -91,7 +92,7 @@ endif
ifeq (NetBSD,$(uname_S))
EV_CONFIG=config_netbsd.h
EIO_CONFIG=config_netbsd.h
-LINKFLAGS+=
+LINKFLAGS+=-lkvm
OBJS += src/unix/netbsd.o
OBJS += src/unix/kqueue.o
endif
diff --git a/deps/uv/gyp_uv b/deps/uv/gyp_uv
index a8528fa91..9c719fde5 100755
--- a/deps/uv/gyp_uv
+++ b/deps/uv/gyp_uv
@@ -60,9 +60,11 @@ if __name__ == '__main__':
# There's a bug with windows which doesn't allow this feature.
if sys.platform != 'win32':
- args.extend(['--generator-output', output_dir])
- args.extend(['-Goutput_dir=' + output_dir])
- args.extend('-f make'.split())
+ if '-f' not in args:
+ args.extend('-f make'.split())
+ if 'ninja' not in args:
+ args.extend(['-Goutput_dir=' + output_dir])
+ args.extend(['--generator-output', output_dir])
(major, minor), is_clang = compiler_version()
args.append('-Dgcc_version=%d' % (10 * major + minor))
args.append('-Dclang=%d' % int(is_clang))
diff --git a/deps/uv/include/uv-private/uv-darwin.h b/deps/uv/include/uv-private/uv-darwin.h
index 7f1b928a6..397c6a97a 100644
--- a/deps/uv/include/uv-private/uv-darwin.h
+++ b/deps/uv/include/uv-private/uv-darwin.h
@@ -29,10 +29,23 @@
# define UV_PLATFORM_SEM_T semaphore_t
#endif
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv_thread_t cf_thread; \
+ void* cf_cb; \
+ void* cf_loop; \
+ uv_mutex_t cf_mutex; \
+ uv_sem_t cf_sem; \
+ ngx_queue_t cf_signals; \
+
#define UV_PLATFORM_FS_EVENT_FIELDS \
ev_io event_watcher; \
int fflags; \
int fd; \
+ void* cf_eventstream; \
+ uv_async_t* cf_cb; \
+ ngx_queue_t cf_events; \
+ uv_sem_t cf_sem; \
+ uv_mutex_t cf_mutex; \
#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
void* select; \
diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h
index 6cdea6724..91ffbe4c9 100644
--- a/deps/uv/include/uv-private/uv-unix.h
+++ b/deps/uv/include/uv-private/uv-unix.h
@@ -137,6 +137,7 @@ typedef struct {
uint64_t time; \
void* signal_ctx; \
uv_signal_t child_watcher; \
+ int emfile_fd; \
UV_PLATFORM_LOOP_FIELDS \
#define UV_REQ_TYPE_PRIVATE /* empty */
diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h
index 4078bcd87..6a7638398 100644
--- a/deps/uv/include/uv.h
+++ b/deps/uv/include/uv.h
@@ -1789,6 +1789,7 @@ UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
UV_EXTERN int uv_thread_create(uv_thread_t *tid,
void (*entry)(void *arg), void *arg);
+UV_EXTERN unsigned long uv_thread_self(void);
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
/* the presence of these unions force similar struct layout */
diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c
index 78c1863ea..63bedf56f 100644
--- a/deps/uv/src/unix/async.c
+++ b/deps/uv/src/unix/async.c
@@ -31,7 +31,7 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* handle, int events);
__attribute__((always_inline))
-inline static int uv__async_make_pending(volatile sig_atomic_t* ptr) {
+static int uv__async_make_pending(volatile sig_atomic_t* ptr) {
/* Do a cheap read first. */
if (*ptr)
return 1;
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c
index 85d5f1644..3ad63f1f8 100644
--- a/deps/uv/src/unix/core.c
+++ b/deps/uv/src/unix/core.c
@@ -463,7 +463,7 @@ int uv__accept(int sockfd) {
while (1) {
#if __linux__
- static __read_mostly int no_accept4;
+ static int no_accept4;
if (no_accept4)
goto skip;
diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c
index b1586a3d6..675a4f6d9 100644
--- a/deps/uv/src/unix/darwin.c
+++ b/deps/uv/src/unix/darwin.c
@@ -43,13 +43,137 @@
static char *process_title;
+/* Forward declarations */
+void uv__cf_loop_runner(void* arg);
+void uv__cf_loop_cb(void* arg);
+
+typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
+struct uv__cf_loop_signal_s {
+ void* arg;
+ cf_loop_signal_cb cb;
+ ngx_queue_t member;
+};
+
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
+ CFRunLoopSourceContext ctx;
+ int r;
+
+ loop->cf_loop = NULL;
+ if ((r = uv_mutex_init(&loop->cf_mutex)))
+ return r;
+ if ((r = uv_sem_init(&loop->cf_sem, 0)))
+ return r;
+ ngx_queue_init(&loop->cf_signals);
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.info = loop;
+ ctx.perform = uv__cf_loop_cb;
+ loop->cf_cb = CFRunLoopSourceCreate(NULL, 0, &ctx);
+
+ if ((r = uv_thread_create(&loop->cf_thread, uv__cf_loop_runner, loop)))
+ return r;
+
+ /* Synchronize threads */
+ uv_sem_wait(&loop->cf_sem);
+ assert(((volatile CFRunLoopRef) loop->cf_loop) != NULL);
+
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
+ ngx_queue_t* item;
+ uv__cf_loop_signal_t* s;
+
+ assert(loop->cf_loop != NULL);
+ CFRunLoopStop(loop->cf_loop);
+ uv_thread_join(&loop->cf_thread);
+ loop->cf_loop = NULL;
+
+ uv_sem_destroy(&loop->cf_sem);
+ uv_mutex_destroy(&loop->cf_mutex);
+
+ /* Free any remaining data */
+ while (!ngx_queue_empty(&loop->cf_signals)) {
+ item = ngx_queue_head(&loop->cf_signals);
+
+ s = ngx_queue_data(item, uv__cf_loop_signal_t, member);
+
+ ngx_queue_remove(item);
+ free(s);
+ }
+}
+
+
+void uv__cf_loop_runner(void* arg) {
+ uv_loop_t* loop;
+
+ loop = arg;
+
+ /* Get thread's loop */
+ *((volatile CFRunLoopRef*)&loop->cf_loop) = CFRunLoopGetCurrent();
+
+ CFRunLoopAddSource(loop->cf_loop,
+ loop->cf_cb,
+ kCFRunLoopDefaultMode);
+
+ uv_sem_post(&loop->cf_sem);
+
+ CFRunLoopRun();
+
+ CFRunLoopRemoveSource(loop->cf_loop,
+ loop->cf_cb,
+ kCFRunLoopDefaultMode);
+}
+
+
+void uv__cf_loop_cb(void* arg) {
+ uv_loop_t* loop;
+ ngx_queue_t* item;
+ ngx_queue_t split_head;
+ uv__cf_loop_signal_t* s;
+
+ loop = arg;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ ngx_queue_init(&split_head);
+ if (!ngx_queue_empty(&loop->cf_signals)) {
+ ngx_queue_t* split_pos = ngx_queue_next(&loop->cf_signals);
+ ngx_queue_split(&loop->cf_signals, split_pos, &split_head);
+ }
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ while (!ngx_queue_empty(&split_head)) {
+ item = ngx_queue_head(&split_head);
+
+ s = ngx_queue_data(item, uv__cf_loop_signal_t, member);
+ s->cb(s->arg);
+
+ ngx_queue_remove(item);
+ free(s);
+ }
+}
+
+
+void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg) {
+ uv__cf_loop_signal_t* item;
+
+ item = malloc(sizeof(*item));
+ /* XXX: Fail */
+ if (item == NULL)
+ abort();
+
+ item->arg = arg;
+ item->cb = cb;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ ngx_queue_insert_tail(&loop->cf_signals, &item->member);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ assert(loop->cf_loop != NULL);
+ CFRunLoopSourceSignal(loop->cf_cb);
+ CFRunLoopWakeUp(loop->cf_loop);
}
diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c
new file mode 100644
index 000000000..1a7e06e46
--- /dev/null
+++ b/deps/uv/src/unix/fsevents.c
@@ -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.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <CoreServices/CoreServices.h>
+
+typedef struct uv__fsevents_event_s uv__fsevents_event_t;
+
+struct uv__fsevents_event_s {
+ int events;
+ ngx_queue_t member;
+ char path[1];
+};
+
+
+#define UV__FSEVENTS_WALK(handle, block) \
+ { \
+ ngx_queue_t* curr; \
+ ngx_queue_t split_head; \
+ uv__fsevents_event_t* event; \
+ uv_mutex_lock(&(handle)->cf_mutex); \
+ ngx_queue_init(&split_head); \
+ if (!ngx_queue_empty(&(handle)->cf_events)) { \
+ ngx_queue_t* split_pos = ngx_queue_next(&(handle)->cf_events); \
+ ngx_queue_split(&(handle)->cf_events, split_pos, &split_head); \
+ } \
+ uv_mutex_unlock(&(handle)->cf_mutex); \
+ while (!ngx_queue_empty(&split_head)) { \
+ curr = ngx_queue_head(&split_head); \
+ /* Invoke callback */ \
+ event = ngx_queue_data(curr, uv__fsevents_event_t, member); \
+ ngx_queue_remove(curr); \
+ /* Invoke block code, but only if handle wasn't closed */ \
+ if (((handle)->flags & (UV_CLOSING | UV_CLOSED)) == 0) \
+ block \
+ /* Free allocated data */ \
+ free(event); \
+ } \
+ }
+
+
+void uv__fsevents_cb(uv_async_t* cb, int status) {
+ uv_fs_event_t* handle;
+
+ handle = cb->data;
+
+ UV__FSEVENTS_WALK(handle, {
+ if (handle->fd != -1)
+ handle->cb(handle, event->path, event->events, 0);
+ })
+
+ if ((handle->flags & (UV_CLOSING | UV_CLOSED)) == 0 && handle->fd == -1)
+ uv__fsevents_close(handle);
+}
+
+
+void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
+ void* info,
+ size_t numEvents,
+ void* eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]) {
+ size_t i;
+ int len;
+ char** paths;
+ uv_fs_event_t* handle;
+ uv__fsevents_event_t* event;
+ ngx_queue_t add_list;
+
+ handle = info;
+ paths = eventPaths;
+ ngx_queue_init(&add_list);
+
+ for (i = 0; i < numEvents; i++) {
+ /* Ignore system events */
+ if (eventFlags[i] & (kFSEventStreamEventFlagUserDropped |
+ kFSEventStreamEventFlagKernelDropped |
+ kFSEventStreamEventFlagEventIdsWrapped |
+ kFSEventStreamEventFlagHistoryDone |
+ kFSEventStreamEventFlagMount |
+ kFSEventStreamEventFlagUnmount)) {
+ continue;
+ }
+
+ /* TODO: Report errors */
+ len = strlen(paths[i]);
+ event = malloc(sizeof(*event) + len);
+ if (event == NULL)
+ break;
+
+ memcpy(event->path, paths[i], len + 1);
+
+ if (eventFlags[i] & kFSEventStreamEventFlagItemModified)
+ event->events = UV_CHANGE;
+ else
+ event->events = UV_RENAME;
+
+ ngx_queue_insert_tail(&add_list, &event->member);
+ }
+ uv_mutex_lock(&handle->cf_mutex);
+ ngx_queue_add(&handle->cf_events, &add_list);
+ uv_mutex_unlock(&handle->cf_mutex);
+
+ uv_async_send(handle->cf_cb);
+}
+
+
+void uv__fsevents_schedule(void* arg) {
+ uv_fs_event_t* handle;
+
+ handle = arg;
+ FSEventStreamScheduleWithRunLoop(handle->cf_eventstream,
+ handle->loop->cf_loop,
+ kCFRunLoopDefaultMode);
+ FSEventStreamStart(handle->cf_eventstream);
+ uv_sem_post(&handle->cf_sem);
+}
+
+
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ FSEventStreamContext ctx;
+ FSEventStreamRef ref;
+ CFStringRef path;
+ CFArrayRef paths;
+ CFAbsoluteTime latency;
+ FSEventStreamCreateFlags flags;
+
+ /* Initialize context */
+ ctx.version = 0;
+ ctx.info = handle;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+
+ /* Initialize paths array */
+ path = CFStringCreateWithCString(NULL,
+ handle->filename,
+ CFStringGetSystemEncoding());
+ paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL);
+
+ latency = 0.15;
+
+ /* Set appropriate flags */
+ flags = kFSEventStreamCreateFlagFileEvents;
+
+ ref = FSEventStreamCreate(NULL,
+ &uv__fsevents_event_cb,
+ &ctx,
+ paths,
+ kFSEventStreamEventIdSinceNow,
+ latency,
+ flags);
+ handle->cf_eventstream = ref;
+
+ /*
+ * Events will occur in other thread.
+ * Initialize callback for getting them back into event loop's thread
+ */
+ handle->cf_cb = malloc(sizeof(*handle->cf_cb));
+ if (handle->cf_cb == NULL)
+ return uv__set_sys_error(handle->loop, ENOMEM);
+
+ handle->cf_cb->data = handle;
+ uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
+ handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
+ uv_unref((uv_handle_t*) handle->cf_cb);
+
+ uv_mutex_init(&handle->cf_mutex);
+ uv_sem_init(&handle->cf_sem, 0);
+ ngx_queue_init(&handle->cf_events);
+
+ uv__cf_loop_signal(handle->loop, uv__fsevents_schedule, handle);
+
+ return 0;
+}
+
+
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ if (handle->cf_eventstream == NULL)
+ return -1;
+
+ /* Ensure that event stream was scheduled */
+ uv_sem_wait(&handle->cf_sem);
+
+ /* Stop emitting events */
+ FSEventStreamStop(handle->cf_eventstream);
+
+ /* Release stream */
+ FSEventStreamInvalidate(handle->cf_eventstream);
+ FSEventStreamRelease(handle->cf_eventstream);
+ handle->cf_eventstream = NULL;
+
+ uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free);
+
+ /* Free data in queue */
+ UV__FSEVENTS_WALK(handle, {
+ /* NOP */
+ })
+
+ uv_mutex_destroy(&handle->cf_mutex);
+ uv_sem_destroy(&handle->cf_sem);
+
+ return 0;
+}
diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h
index e2668109d..4abfedde3 100644
--- a/deps/uv/src/unix/internal.h
+++ b/deps/uv/src/unix/internal.h
@@ -28,12 +28,6 @@
#include <assert.h>
#include <stdlib.h> /* abort */
-#if defined(__GNUC__)
-# define __read_mostly __attribute__((__section__(".data.read_mostly")))
-#else
-# define __read_mostly
-#endif
-
#if defined(__STRICT_ANSI__)
# define inline __inline
#endif
@@ -108,9 +102,9 @@ enum {
UV_LOOP_EIO_INITIALIZED = 1
};
-inline static void uv__req_init(uv_loop_t* loop,
- uv_req_t* req,
- uv_req_type type) {
+__attribute__((unused))
+__attribute__((always_inline))
+static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) {
req->type = type;
uv__req_register(loop, req);
}
@@ -195,4 +189,32 @@ void uv__udp_finish_close(uv_udp_t* handle);
int uv__make_socketpair(int fds[2], int flags);
int uv__make_pipe(int fds[2], int flags);
+#if defined(__APPLE__)
+typedef void (*cf_loop_signal_cb)(void*);
+
+void uv__cf_loop_signal(uv_loop_t* loop, cf_loop_signal_cb cb, void* arg);
+
+int uv__fsevents_init(uv_fs_event_t* handle);
+int uv__fsevents_close(uv_fs_event_t* handle);
+
+/* OSX < 10.7 has no file events, polyfill them */
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
+
+static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
+static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
+static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
+static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
+static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
+static const int kFSEventStreamEventFlagItemModified = 0x00001000;
+static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
+static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
+static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
+static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
+static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
+static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
+
+#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
+
+#endif /* defined(__APPLE__) */
+
#endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c
index be68b5867..b79dce3c2 100644
--- a/deps/uv/src/unix/kqueue.c
+++ b/deps/uv/src/unix/kqueue.c
@@ -89,6 +89,9 @@ int uv_fs_event_init(uv_loop_t* loop,
uv_fs_event_cb cb,
int flags) {
int fd;
+#if defined(__APPLE__)
+ struct stat statbuf;
+#endif /* defined(__APPLE__) */
/* We don't support any flags yet. */
assert(!flags);
@@ -105,6 +108,22 @@ int uv_fs_event_init(uv_loop_t* loop,
handle->fflags = 0;
handle->cb = cb;
handle->fd = fd;
+
+#if defined(__APPLE__)
+ /* Nullify field to perform checks later */
+ handle->cf_eventstream = NULL;
+
+ if (fstat(fd, &statbuf))
+ goto fallback;
+ /* FSEvents works only with directories */
+ if (!(statbuf.st_mode & S_IFDIR))
+ goto fallback;
+
+ return uv__fsevents_init(handle);
+
+fallback:
+#endif /* defined(__APPLE__) */
+
uv__fs_event_start(handle);
return 0;
@@ -112,7 +131,13 @@ int uv_fs_event_init(uv_loop_t* loop,
void uv__fs_event_close(uv_fs_event_t* handle) {
+#if defined(__APPLE__)
+ if (uv__fsevents_close(handle))
+ uv__fs_event_stop(handle);
+#else
uv__fs_event_stop(handle);
+#endif /* defined(__APPLE__) */
+
uv__handle_stop(handle);
free(handle->filename);
close(handle->fd);
diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c
index 70cdc824c..5cd3bd0c8 100644
--- a/deps/uv/src/unix/loop.c
+++ b/deps/uv/src/unix/loop.c
@@ -51,6 +51,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
loop->time = uv_hrtime() / 1000000;
loop->async_pipefd[0] = -1;
loop->async_pipefd[1] = -1;
+ loop->emfile_fd = -1;
loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags);
ev_set_userdata(loop->ev, loop);
eio_channel_init(&loop->uv_eio_channel, loop);
@@ -73,4 +74,9 @@ void uv__loop_delete(uv_loop_t* loop) {
uv__platform_loop_delete(loop);
uv__signal_unregister(loop);
ev_loop_destroy(loop->ev);
+
+ if (loop->emfile_fd != -1) {
+ close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+ }
}
diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c
index b1c437bf4..dab1b696b 100644
--- a/deps/uv/src/unix/netbsd.c
+++ b/deps/uv/src/unix/netbsd.c
@@ -19,11 +19,21 @@
*/
#include "uv.h"
+#include "internal.h"
#include <assert.h>
#include <string.h>
#include <errno.h>
+#include <kvm.h>
+#include <paths.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <net/if.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/sysctl.h>
@@ -34,6 +44,8 @@
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
+static char *process_title;
+
int uv__platform_loop_init(uv_loop_t* loop, int default_loop) {
return 0;
@@ -50,18 +62,20 @@ uint64_t uv_hrtime(void) {
return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
}
+
void uv_loadavg(double avg[3]) {
struct loadavg info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_LOADAVG};
- if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
avg[0] = (double) info.ldavg[0] / info.fscale;
avg[1] = (double) info.ldavg[1] / info.fscale;
avg[2] = (double) info.ldavg[2] / info.fscale;
}
+
int uv_exepath(char* buffer, size_t* size) {
int mib[4];
size_t cb;
@@ -78,7 +92,7 @@ int uv_exepath(char* buffer, size_t* size) {
mib[3] = KERN_PROC_ARGV;
cb = *size;
- if (sysctl(mib, 4, buffer, &cb, NULL, 0) < 0) {
+ if (sysctl(mib, 4, buffer, &cb, NULL, 0) == -1) {
*size = 0;
return -1;
}
@@ -87,18 +101,20 @@ int uv_exepath(char* buffer, size_t* size) {
return 0;
}
+
uint64_t uv_get_free_memory(void) {
struct uvmexp info;
size_t size = sizeof(info);
int which[] = {CTL_VM, VM_UVMEXP};
- if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) {
return -1;
}
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
}
+
uint64_t uv_get_total_memory(void) {
#if defined(HW_PHYSMEM64)
uint64_t info;
@@ -109,9 +125,229 @@ uint64_t uv_get_total_memory(void) {
#endif
size_t size = sizeof(info);
- if (sysctl(which, 2, &info, &size, NULL, 0) < 0) {
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) {
return -1;
}
return (uint64_t) info;
}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+uv_err_t uv_set_process_title(const char* title) {
+ if (process_title) free(process_title);
+
+ process_title = strdup(title);
+ setproctitle("%s", title);
+
+ return uv_ok_;
+}
+
+
+uv_err_t uv_get_process_title(char* buffer, size_t size) {
+ if (process_title) {
+ strncpy(buffer, process_title, size);
+ } else {
+ if (size > 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return uv_ok_;
+}
+
+
+uv_err_t uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc2 *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ int max_size = sizeof(struct kinfo_proc2);
+ int page_size;
+
+ page_size = getpagesize();
+ pid = getpid();
+
+ kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
+
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
+ if (kinfo == NULL) goto error;
+
+ *rss = kinfo->p_vm_rssize * page_size;
+
+ kvm_close(kd);
+
+ return uv_ok_;
+
+error:
+ if (kd) kvm_close(kd);
+ return uv__new_sys_error(errno);
+}
+
+
+uv_err_t uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) {
+ return uv__new_sys_error(errno);
+ }
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return uv_ok_;
+}
+
+
+uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
+ unsigned int multiplier = ((uint64_t)1000L / ticks);
+ unsigned int cur = 0;
+ uv_cpu_info_t* cpu_info;
+ u_int64_t* cp_times;
+ char model[512];
+ u_int64_t cpuspeed;
+ int numcpus;
+ size_t size;
+ int i;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) == -1 &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0) == -1) {
+ return uv__new_sys_error(errno);
+ }
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0) == -1) {
+ return uv__new_sys_error(errno);
+ }
+ *count = numcpus;
+
+ /* Only i386 and amd64 have machdep.tsc_freq */
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0) == -1) {
+ cpuspeed = 0;
+ }
+
+ size = numcpus * CPUSTATES * sizeof(*cp_times);
+ cp_times = malloc(size);
+ if (cp_times == NULL) {
+ return uv__new_artificial_error(UV_ENOMEM);
+ }
+ if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0) == -1) {
+ return uv__new_sys_error(errno);
+ }
+
+ *cpu_infos = malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ free(cp_times);
+ free(*cpu_infos);
+ return uv__new_artificial_error(UV_ENOMEM);
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+ cpu_info->model = strdup(model);
+ cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
+ cur += CPUSTATES;
+ }
+ free(cp_times);
+ return uv_ok_;
+}
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ free(cpu_infos[i].model);
+ }
+
+ free(cpu_infos);
+}
+
+
+uv_err_t uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs *addrs;
+ struct ifaddrs *ent;
+ uv_interface_address_t* address;
+
+ if (getifaddrs(&addrs) != 0) {
+ return uv__new_sys_error(errno);
+ }
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING) ||
+ (ent->ifa_addr == NULL) ||
+ (ent->ifa_addr->sa_family != PF_INET)) {
+ continue;
+ }
+ (*count)++;
+ }
+
+ *addresses = malloc(*count * sizeof(**addresses));
+
+ if (!(*addresses)) {
+ return uv__new_artificial_error(UV_ENOMEM);
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (!(ent->ifa_flags & IFF_UP && ent->ifa_flags & IFF_RUNNING)) {
+ continue;
+ }
+
+ if (ent->ifa_addr == NULL) {
+ continue;
+ }
+
+ if (ent->ifa_addr->sa_family != PF_INET) {
+ continue;
+ }
+
+ address->name = strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6 *)ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in *)ent->ifa_addr);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK) ? 1 : 0;
+
+ address++;
+ }
+
+ freeifaddrs(addrs);
+
+ return uv_ok_;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ free(addresses[i].name);
+ }
+
+ free(addresses);
+}
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
index 829f79aaf..7c552a736 100644
--- a/deps/uv/src/unix/process.c
+++ b/deps/uv/src/unix/process.c
@@ -117,7 +117,7 @@ static void uv__chld(uv_signal_t* handle, int signum) {
int uv__make_socketpair(int fds[2], int flags) {
#if __linux__
- static __read_mostly int no_cloexec;
+ static int no_cloexec;
if (no_cloexec)
goto skip;
@@ -153,7 +153,7 @@ skip:
int uv__make_pipe(int fds[2], int flags) {
#if __linux__
- static __read_mostly int no_pipe2;
+ static int no_pipe2;
if (no_pipe2)
goto skip;
diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c
index 344118569..5321d90f4 100644
--- a/deps/uv/src/unix/stream.c
+++ b/deps/uv/src/unix/stream.c
@@ -62,6 +62,29 @@ static void uv__read(uv_stream_t* stream);
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, int events);
+/* Used by the accept() EMFILE party trick. */
+static int uv__open_cloexec(const char* path, int flags) {
+ int fd;
+
+#if defined(__linux__)
+ fd = open(path, flags | UV__O_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != EINVAL)
+ return -1;
+
+ /* O_CLOEXEC not supported. */
+#endif
+
+ fd = open(path, flags);
+ if (fd != -1)
+ uv__cloexec(fd, 1);
+
+ return fd;
+}
+
+
static size_t uv__buf_count(uv_buf_t bufs[], int bufcnt) {
size_t total = 0;
int i;
@@ -90,6 +113,9 @@ void uv__stream_init(uv_loop_t* loop,
ngx_queue_init(&stream->write_completed_queue);
stream->write_queue_size = 0;
+ if (loop->emfile_fd == -1)
+ loop->emfile_fd = uv__open_cloexec("/", O_RDONLY);
+
#if defined(__APPLE__)
stream->select = NULL;
#endif /* defined(__APPLE_) */
@@ -370,10 +396,56 @@ static void uv__next_accept(uv_idle_t* idle, int status) {
}
+/* Implements a best effort approach to mitigating accept() EMFILE errors.
+ * We have a spare file descriptor stashed away that we close to get below
+ * the EMFILE limit. Next, we accept all pending connections and close them
+ * immediately to signal the clients that we're overloaded - and we are, but
+ * we still keep on trucking.
+ *
+ * There is one caveat: it's not reliable in a multi-threaded environment.
+ * The file descriptor limit is per process. Our party trick fails if another
+ * thread opens a file or creates a socket in the time window between us
+ * calling close() and accept().
+ */
+static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
+ int fd;
+ int r;
+
+ if (loop->emfile_fd == -1)
+ return -1;
+
+ close(loop->emfile_fd);
+
+ for (;;) {
+ fd = uv__accept(accept_fd);
+
+ if (fd != -1) {
+ close(fd);
+ continue;
+ }
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ r = 0;
+ else
+ r = -1;
+
+ loop->emfile_fd = uv__open_cloexec("/", O_RDONLY);
+
+ return r;
+ }
+}
+
+
void uv__server_io(uv_loop_t* loop, uv__io_t* w, int events) {
+ static int use_emfile_trick = -1;
+ uv_stream_t* stream;
int fd;
- uv_stream_t* stream = container_of(w, uv_stream_t, read_watcher);
+ int r;
+ stream = container_of(w, uv_stream_t, read_watcher);
assert(events == UV__IO_READ);
assert(!(stream->flags & UV_CLOSING));
@@ -389,31 +461,48 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, int events) {
assert(stream->accepted_fd < 0);
fd = uv__accept(stream->fd);
- if (fd < 0) {
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- /* No problem. */
- return;
- } else if (errno == EMFILE) {
- /* TODO special trick. unlock reserved socket, accept, close. */
- return;
- } else if (errno == ECONNABORTED) {
- /* ignore */
+ if (fd == -1) {
+ switch (errno) {
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EAGAIN:
+ return; /* Not an error. */
+
+ case ECONNABORTED:
+ continue; /* Ignore. */
+
+ case EMFILE:
+ case ENFILE:
+ if (use_emfile_trick == -1) {
+ const char* val = getenv("UV_ACCEPT_EMFILE_TRICK");
+ use_emfile_trick = (val == NULL || atoi(val) != 0);
+ }
+
+ if (use_emfile_trick) {
+ SAVE_ERRNO(r = uv__emfile_trick(loop, stream->fd));
+ if (r == 0)
+ continue;
+ }
+
+ /* Fall through. */
+
+ default:
+ uv__set_sys_error(loop, errno);
+ stream->connection_cb(stream, -1);
continue;
- } else {
- uv__set_sys_error(stream->loop, errno);
- stream->connection_cb((uv_stream_t*)stream, -1);
- }
- } else {
- stream->accepted_fd = fd;
- stream->connection_cb(stream, 0);
-
- if (stream->accepted_fd != -1 ||
- (stream->type == UV_TCP && stream->flags == UV_TCP_SINGLE_ACCEPT)) {
- /* The user hasn't yet accepted called uv_accept() */
- uv__io_stop(stream->loop, &stream->read_watcher);
- break;
}
}
+
+ stream->accepted_fd = fd;
+ stream->connection_cb(stream, 0);
+
+ if (stream->accepted_fd != -1 ||
+ (stream->type == UV_TCP && stream->flags == UV_TCP_SINGLE_ACCEPT)) {
+ /* The user hasn't yet accepted called uv_accept() */
+ uv__io_stop(loop, &stream->read_watcher);
+ break;
+ }
}
if (stream->fd != -1 &&
diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c
index 441473cda..186150be5 100644
--- a/deps/uv/src/unix/tcp.c
+++ b/deps/uv/src/unix/tcp.c
@@ -247,6 +247,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
if (uv_idle_init(tcp->loop, tcp->idle_handle))
abort();
+ tcp->idle_handle->flags |= UV__HANDLE_INTERNAL;
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
@@ -331,7 +332,10 @@ int uv__tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
}
#endif
-#ifdef TCP_KEEPALIVE
+ /* Solaris/SmartOS, if you don't support keep-alive,
+ * then don't advertise it in your system headers...
+ */
+#if defined(TCP_KEEPALIVE) && !defined(__sun)
if (enable && setsockopt(handle->fd,
IPPROTO_TCP,
TCP_KEEPALIVE,
diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c
index 75dfcd89c..dd91dbb28 100644
--- a/deps/uv/src/uv-common.c
+++ b/deps/uv/src/uv-common.c
@@ -314,6 +314,15 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
}
+unsigned long uv_thread_self(void) {
+#ifdef _WIN32
+ return (unsigned long) GetCurrentThreadId();
+#else
+ return (unsigned long) pthread_self();
+#endif
+}
+
+
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
ngx_queue_t* q;
uv_handle_t* h;
diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c
index 9a83ea897..a9e0e7fbd 100644
--- a/deps/uv/src/win/error.c
+++ b/deps/uv/src/win/error.c
@@ -144,6 +144,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERROR_BAD_PIPE: return UV_EPIPE;
case ERROR_NO_DATA: return UV_EPIPE;
case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
+ case WSAESHUTDOWN: return UV_EPIPE;
case ERROR_PIPE_BUSY: return UV_EBUSY;
case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
case WSAETIMEDOUT: return UV_ETIMEDOUT;
diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h
index b0d1d18ed..fe3889062 100644
--- a/deps/uv/src/win/internal.h
+++ b/deps/uv/src/win/internal.h
@@ -52,9 +52,8 @@
#define UV_HANDLE_LISTENING 0x00000800
#define UV_HANDLE_CONNECTION 0x00001000
#define UV_HANDLE_CONNECTED 0x00002000
-#define UV_HANDLE_EOF 0x00004000
-#define UV_HANDLE_SHUTTING 0x00008000
-#define UV_HANDLE_SHUT 0x00010000
+#define UV_HANDLE_READABLE 0x00008000
+#define UV_HANDLE_WRITABLE 0x00010000
#define UV_HANDLE_READ_PENDING 0x00020000
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
#define UV_HANDLE_ZERO_READ 0x00080000
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
index 62cdef544..819091efe 100644
--- a/deps/uv/src/win/pipe.c
+++ b/deps/uv/src/win/pipe.c
@@ -114,7 +114,7 @@ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
FILE_FLAG_OVERLAPPED,
NULL);
if (pipeHandle != INVALID_HANDLE_VALUE) {
- *duplex_flags = 0;
+ *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
return pipeHandle;
}
@@ -133,7 +133,7 @@ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
NULL);
if (pipeHandle != INVALID_HANDLE_VALUE) {
- *duplex_flags = UV_HANDLE_SHUTTING;
+ *duplex_flags = UV_HANDLE_READABLE;
return pipeHandle;
}
}
@@ -148,7 +148,7 @@ static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
NULL);
if (pipeHandle != INVALID_HANDLE_VALUE) {
- *duplex_flags = UV_HANDLE_EOF;
+ *duplex_flags = UV_HANDLE_WRITABLE;
return pipeHandle;
}
}
@@ -316,7 +316,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
/* Failure */
UNREGISTER_HANDLE_REQ(loop, handle, req);
- handle->flags &= ~UV_HANDLE_SHUTTING;
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
if (req->cb) {
uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status));
req->cb(req, -1);
@@ -343,7 +343,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
/* Failure. */
UNREGISTER_HANDLE_REQ(loop, handle, req);
- handle->flags &= ~UV_HANDLE_SHUTTING;
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
if (req->cb) {
uv__set_sys_error(loop, GetLastError());
req->cb(req, -1);
@@ -630,7 +630,7 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
}
if (handle->flags & UV_HANDLE_CONNECTION) {
- handle->flags |= UV_HANDLE_SHUTTING;
+ handle->flags &= ~UV_HANDLE_WRITABLE;
eof_timer_destroy(handle);
}
@@ -659,6 +659,7 @@ void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);
}
@@ -746,6 +747,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
/* Initialize the client handle and copy the pipeHandle to the client */
uv_pipe_connection_init(pipe_client);
pipe_client->handle = req->pipeHandle;
+ pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
/* Prepare the req to pick up a new connection */
server->pending_accepts = req->next_pending;
@@ -964,16 +966,6 @@ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb, uv_read2_cb read2_cb) {
uv_loop_t* loop = handle->loop;
- if (!(handle->flags & UV_HANDLE_CONNECTION)) {
- uv__set_artificial_error(loop, UV_EINVAL);
- return -1;
- }
-
- if (handle->flags & UV_HANDLE_EOF) {
- uv__set_artificial_error(loop, UV_EOF);
- return -1;
- }
-
handle->flags |= UV_HANDLE_READING;
INCREASE_ACTIVE_COUNT(loop, handle);
handle->read_cb = read_cb;
@@ -1072,16 +1064,6 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
assert(handle->handle != INVALID_HANDLE_VALUE);
- if (!(handle->flags & UV_HANDLE_CONNECTION)) {
- uv__set_artificial_error(loop, UV_EINVAL);
- return -1;
- }
-
- if (handle->flags & UV_HANDLE_SHUTTING) {
- uv__set_artificial_error(loop, UV_EOF);
- return -1;
- }
-
uv_req_init(loop, (uv_req_t*) req);
req->type = UV_WRITE;
req->handle = (uv_stream_t*) handle;
@@ -1253,7 +1235,7 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
/* so discard it. */
eof_timer_destroy(handle);
- handle->flags |= UV_HANDLE_EOF;
+ handle->flags &= ~UV_HANDLE_READABLE;
uv_read_stop((uv_stream_t*) handle);
uv__set_artificial_error(loop, UV_EOF);
@@ -1483,8 +1465,8 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_queue_non_overlapped_write(handle);
}
- if (handle->write_reqs_pending == 0 &&
- handle->flags & UV_HANDLE_SHUTTING) {
+ if (handle->shutdown_req != NULL &&
+ handle->write_reqs_pending == 0) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
@@ -1548,7 +1530,7 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
/* Initialize and optionally start the eof timer. */
/* This makes no sense if we've already seen EOF. */
- if (!(handle->flags & UV_HANDLE_EOF)) {
+ if (handle->flags & UV_HANDLE_READABLE) {
eof_timer_init(handle);
/* If reading start the timer right now. */
@@ -1662,6 +1644,7 @@ void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
uv_pipe_connection_init(pipe);
pipe->handle = os_handle;
+ pipe->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
if (pipe->ipc) {
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
diff --git a/deps/uv/src/win/process-stdio.c b/deps/uv/src/win/process-stdio.c
index 777774047..89e2cd990 100644
--- a/deps/uv/src/win/process-stdio.c
+++ b/deps/uv/src/win/process-stdio.c
@@ -163,6 +163,9 @@ static uv_err_t uv__create_stdio_pipe_pair(uv_loop_t* loop,
}
}
+ /* The server end is now readable and writable. */
+ server_pipe->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+
*child_pipe_ptr = child_pipe;
return uv_ok_;
diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c
index 195e0b801..097f34979 100644
--- a/deps/uv/src/win/stream.c
+++ b/deps/uv/src/win/stream.c
@@ -55,6 +55,16 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
+ if (handle->flags & UV_HANDLE_READING) {
+ uv__set_sys_error(handle->loop, UV_EALREADY);
+ return -1;
+ }
+
+ if (!(handle->flags & UV_HANDLE_READABLE)) {
+ uv__set_artificial_error(handle->loop, UV_ENOTCONN);
+ return -1;
+ }
+
switch (handle->type) {
case UV_TCP:
return uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
@@ -71,6 +81,16 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
uv_read2_cb read_cb) {
+ if (handle->flags & UV_HANDLE_READING) {
+ uv__set_sys_error(handle->loop, UV_EALREADY);
+ return -1;
+ }
+
+ if (!(handle->flags & UV_HANDLE_READABLE)) {
+ uv__set_artificial_error(handle->loop, UV_ENOTCONN);
+ return -1;
+ }
+
switch (handle->type) {
case UV_NAMED_PIPE:
return uv_pipe_read2_start((uv_pipe_t*)handle, alloc_cb, read_cb);
@@ -82,14 +102,15 @@ int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
int uv_read_stop(uv_stream_t* handle) {
+ if (!(handle->flags & UV_HANDLE_READING))
+ return 0;
+
if (handle->type == UV_TTY) {
return uv_tty_read_stop((uv_tty_t*) handle);
- } else if (handle->flags & UV_HANDLE_READING) {
+ } else {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(handle->loop, handle);
return 0;
- } else {
- return 0;
}
}
@@ -98,6 +119,11 @@ int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
uv_write_cb cb) {
uv_loop_t* loop = handle->loop;
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ uv__set_artificial_error(loop, UV_EPIPE);
+ return -1;
+ }
+
switch (handle->type) {
case UV_TCP:
return uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, bufcnt, cb);
@@ -117,6 +143,11 @@ int uv_write2(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
uv_stream_t* send_handle, uv_write_cb cb) {
uv_loop_t* loop = handle->loop;
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ uv__set_artificial_error(loop, UV_EPIPE);
+ return -1;
+ }
+
switch (handle->type) {
case UV_NAMED_PIPE:
return uv_pipe_write2(loop, req, (uv_pipe_t*) handle, bufs, bufcnt, send_handle, cb);
@@ -131,13 +162,13 @@ int uv_write2(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop;
- if (!(handle->flags & UV_HANDLE_CONNECTION)) {
- uv__set_sys_error(loop, WSAEINVAL);
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ uv__set_artificial_error(loop, UV_EPIPE);
return -1;
}
- if (handle->flags & UV_HANDLE_SHUTTING) {
- uv__set_sys_error(loop, WSAESHUTDOWN);
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ uv__set_artificial_error(loop, UV_EPIPE);
return -1;
}
@@ -146,7 +177,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
req->handle = handle;
req->cb = cb;
- handle->flags |= UV_HANDLE_SHUTTING;
+ handle->flags &= ~UV_HANDLE_WRITABLE;
handle->shutdown_req = req;
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
@@ -158,10 +189,10 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
int uv_is_readable(const uv_stream_t* handle) {
- return !(handle->flags & UV_HANDLE_EOF);
+ return !!(handle->flags & UV_HANDLE_READABLE);
}
int uv_is_writable(const uv_stream_t* handle) {
- return !(handle->flags & UV_HANDLE_SHUTTING);
+ return !!(handle->flags & UV_HANDLE_WRITABLE);
}
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
index 111f03c4a..0bc01c613 100644
--- a/deps/uv/src/win/tcp.c
+++ b/deps/uv/src/win/tcp.c
@@ -169,7 +169,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
uv__set_artificial_error(loop, UV_ECANCELED);
} else if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) {
status = 0;
- handle->flags |= UV_HANDLE_SHUT;
} else {
status = -1;
uv__set_sys_error(loop, WSAGetLastError());
@@ -605,7 +604,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
} else {
uv_connection_init((uv_stream_t*) client);
/* AcceptEx() implicitly binds the accepted socket. */
- client->flags |= UV_HANDLE_BOUND;
+ client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
}
/* Prepare the req to pick up a new connection */
@@ -646,21 +645,6 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
uv_loop_t* loop = handle->loop;
- if (!(handle->flags & UV_HANDLE_CONNECTION)) {
- uv__set_sys_error(loop, WSAEINVAL);
- return -1;
- }
-
- if (handle->flags & UV_HANDLE_READING) {
- uv__set_sys_error(loop, WSAEALREADY);
- return -1;
- }
-
- if (handle->flags & UV_HANDLE_EOF) {
- uv__set_sys_error(loop, WSAESHUTDOWN);
- return -1;
- }
-
handle->flags |= UV_HANDLE_READING;
handle->read_cb = read_cb;
handle->alloc_cb = alloc_cb;
@@ -855,16 +839,6 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
int result;
DWORD bytes;
- if (!(handle->flags & UV_HANDLE_CONNECTION)) {
- uv__set_sys_error(loop, WSAEINVAL);
- return -1;
- }
-
- if (handle->flags & UV_HANDLE_SHUTTING) {
- uv__set_sys_error(loop, WSAESHUTDOWN);
- return -1;
- }
-
uv_req_init(loop, (uv_req_t*) req);
req->type = UV_WRITE;
req->handle = (uv_stream_t*) handle;
@@ -970,7 +944,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(loop, handle);
}
- handle->flags |= UV_HANDLE_EOF;
+ handle->flags &= ~UV_HANDLE_READABLE;
uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
buf.base = 0;
@@ -1001,9 +975,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
}
} else {
/* Connection closed */
- handle->flags &= ~UV_HANDLE_READING;
+ handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
DECREASE_ACTIVE_COUNT(loop, handle);
- handle->flags |= UV_HANDLE_EOF;
uv__set_error(loop, UV_EOF, ERROR_SUCCESS);
handle->read_cb((uv_stream_t*)handle, -1, buf);
@@ -1070,7 +1043,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
}
handle->write_reqs_pending--;
- if (handle->flags & UV_HANDLE_SHUTTING &&
+ if (handle->shutdown_req != NULL &&
handle->write_reqs_pending == 0) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
@@ -1139,6 +1112,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
NULL,
0) == 0) {
uv_connection_init((uv_stream_t*)handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
loop->active_tcp_streams++;
((uv_connect_cb)req->cb)(req, 0);
} else {
@@ -1181,6 +1155,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
if (tcp_connection) {
uv_connection_init((uv_stream_t*)tcp);
+ tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
}
tcp->flags |= UV_HANDLE_BOUND;
@@ -1342,7 +1317,6 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
/* Just do shutdown on non-shared sockets, which ensures graceful close. */
shutdown(tcp->socket, SD_SEND);
- tcp->flags |= UV_HANDLE_SHUT;
} else if (uv_tcp_try_cancel_io(tcp) == 0) {
/* In case of a shared socket, we try to cancel all outstanding I/O, */
@@ -1397,6 +1371,7 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
}
+ tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(tcp);
if (tcp->reqs_pending == 0) {
diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c
index 19edf7d29..7a84506fd 100644
--- a/deps/uv/src/win/tty.c
+++ b/deps/uv/src/win/tty.c
@@ -140,7 +140,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
if (readable) {
/* Initialize TTY input specific fields. */
tty->original_console_mode = original_console_mode;
- tty->flags |= UV_HANDLE_TTY_READABLE;
+ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
tty->read_line_handle = NULL;
tty->read_line_buffer = uv_null_buf_;
tty->read_raw_wait = NULL;
@@ -152,6 +152,8 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
} else {
/* TTY output specific fields. */
+ tty->flags |= UV_HANDLE_READABLE;
+
/* Init utf8-to-utf16 conversion state. */
tty->utf8_bytes_left = 0;
tty->utf8_codepoint = 0;
@@ -826,15 +828,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
int uv_tty_read_stop(uv_tty_t* handle) {
uv_loop_t* loop = handle->loop;
- if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
- uv__set_artificial_error(handle->loop, UV_EINVAL);
- return -1;
- }
- if (handle->flags & UV_HANDLE_READING) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- }
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
/* Cancel raw read */
if ((handle->flags & UV_HANDLE_READ_PENDING) &&
@@ -1750,17 +1746,6 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
DWORD error;
- if (handle->flags & UV_HANDLE_TTY_READABLE) {
- uv__set_artificial_error(handle->loop, UV_EINVAL);
- return -1;
- }
-
- if ((handle->flags & UV_HANDLE_SHUTTING) ||
- (handle->flags & UV_HANDLE_CLOSING)) {
- uv__set_sys_error(loop, WSAESHUTDOWN);
- return -1;
- }
-
uv_req_init(loop, (uv_req_t*) req);
req->type = UV_WRITE;
req->handle = (uv_stream_t*) handle;
@@ -1796,7 +1781,7 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
}
handle->write_reqs_pending--;
- if (handle->flags & UV_HANDLE_SHUTTING &&
+ if (handle->shutdown_req != NULL &&
handle->write_reqs_pending == 0) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
@@ -1808,14 +1793,10 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
void uv_tty_close(uv_tty_t* handle) {
CloseHandle(handle->handle);
- if (handle->flags & UV_HANDLE_TTY_READABLE) {
- /* Readable TTY handle */
+ if (handle->flags & UV_HANDLE_READING)
uv_tty_read_stop(handle);
- } else {
- /* Writable TTY handle */
- handle->flags |= UV_HANDLE_SHUTTING;
- }
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);
if (handle->reqs_pending == 0) {
diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c
index 4d4cfbc31..257d64ca5 100644
--- a/deps/uv/test/test-fs-event.c
+++ b/deps/uv/test/test-fs-event.c
@@ -98,7 +98,8 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
ASSERT(handle == &fs_event);
ASSERT(status == 0);
ASSERT(events == UV_RENAME);
- ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
+ ASSERT(filename == NULL || strcmp(filename, "file1") == 0 ||
+ strstr(filename, "watch_dir") != NULL);
uv_close((uv_handle_t*)handle, close_cb);
}
diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp
index 8ce01ebfd..e44087a57 100644
--- a/deps/uv/uv.gyp
+++ b/deps/uv/uv.gyp
@@ -147,7 +147,7 @@
'libraries': [ '-lm' ]
}],
[ 'OS=="mac"', {
- 'sources': [ 'src/unix/darwin.c' ],
+ 'sources': [ 'src/unix/darwin.c', 'src/unix/fsevents.c' ],
'direct_dependent_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/CoreServices.framework',
@@ -209,6 +209,18 @@
'EIO_CONFIG_H="config_openbsd.h"',
],
}],
+ [ 'OS=="netbsd"', {
+ 'sources': [ 'src/unix/netbsd.c' ],
+ 'defines': [
+ 'EV_CONFIG_H="config_netbsd.h"',
+ 'EIO_CONFIG_H="config_netbsd.h"',
+ ],
+ 'direct_dependent_settings': {
+ 'libraries': [
+ '-lkvm',
+ ],
+ },
+ }],
[ 'OS=="mac" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', {
'sources': [ 'src/unix/kqueue.c' ],
}],