summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy J Fontaine <tjfontaine@gmail.com>2013-10-18 13:52:15 -0700
committerTimothy J Fontaine <tjfontaine@gmail.com>2013-10-18 13:52:15 -0700
commit8fc48bcf4ca49f16b910b388481030870f78665f (patch)
treed7028bb38e1cf5e9deabe9480e4d7c433bd0a76b
parentb97c28f59ee898a81f0df988c249359c9b42701d (diff)
downloadnode-new-8fc48bcf4ca49f16b910b388481030870f78665f.tar.gz
uv: Upgrade to v0.10.18
-rw-r--r--deps/uv/ChangeLog15
-rw-r--r--deps/uv/include/uv-private/uv-darwin.h10
-rw-r--r--deps/uv/src/unix/darwin.c131
-rw-r--r--deps/uv/src/unix/fsevents.c655
-rw-r--r--deps/uv/src/unix/internal.h4
-rw-r--r--deps/uv/src/unix/kqueue.c2
-rw-r--r--deps/uv/src/unix/process.c17
-rw-r--r--deps/uv/src/unix/signal.c5
-rw-r--r--deps/uv/src/version.c2
9 files changed, 301 insertions, 540 deletions
diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog
index 98fb44f978..794764e7d5 100644
--- a/deps/uv/ChangeLog
+++ b/deps/uv/ChangeLog
@@ -1,4 +1,17 @@
-2013.09.25, Version 0.10.17 (Stable)
+2013.10.19, Version 0.10.18 (Stable)
+
+Changes since version 0.10.17:
+
+* unix: fix uv_spawn() NULL pointer deref on ENOMEM (Ben Noordhuis)
+
+* unix: don't close inherited fds on uv_spawn() fail (Ben Noordhuis)
+
+* unix: revert recent FSEvent changes (Ben Noordhuis)
+
+* unix: fix non-synchronized access in signal.c (Ben Noordhuis)
+
+
+2013.09.25, Version 0.10.17 (Stable), 9670e0a93540c2f0d86c84a375f2303383c11e7e
Changes since version 0.10.16:
diff --git a/deps/uv/include/uv-private/uv-darwin.h b/deps/uv/include/uv-private/uv-darwin.h
index 4037f5c51f..e861cbab9a 100644
--- a/deps/uv/include/uv-private/uv-darwin.h
+++ b/deps/uv/include/uv-private/uv-darwin.h
@@ -36,8 +36,8 @@
#define UV_PLATFORM_LOOP_FIELDS \
uv_thread_t cf_thread; \
- void* _cf_reserved; \
- void* cf_state; \
+ void* cf_cb; \
+ void* cf_loop; \
uv_mutex_t cf_mutex; \
uv_sem_t cf_sem; \
ngx_queue_t cf_signals; \
@@ -47,10 +47,10 @@
char* realpath; \
int realpath_len; \
int cf_flags; \
- void* cf_event; \
+ void* cf_eventstream; \
uv_async_t* cf_cb; \
- ngx_queue_t cf_member; \
- uv_sem_t _cf_reserved; \
+ ngx_queue_t cf_events; \
+ uv_sem_t cf_sem; \
uv_mutex_t cf_mutex; \
#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c
index 08da5139c1..77e662f4e1 100644
--- a/deps/uv/src/unix/darwin.c
+++ b/deps/uv/src/unix/darwin.c
@@ -28,6 +28,8 @@
#include <ifaddrs.h>
#include <net/if.h>
+#include <CoreFoundation/CFRunLoop.h>
+
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
@@ -35,19 +37,144 @@
#include <sys/sysctl.h>
#include <unistd.h> /* sysconf */
+/* Forward declarations */
+static void uv__cf_loop_runner(void* arg);
+static 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) {
- loop->cf_state = NULL;
+ CFRunLoopSourceContext ctx;
+ int r;
if (uv__kqueue_init(loop))
return -1;
+ 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(ACCESS_ONCE(CFRunLoopRef, loop->cf_loop) != NULL);
+
return 0;
}
void uv__platform_loop_delete(uv_loop_t* loop) {
- uv__fsevents_loop_delete(loop);
+ ngx_queue_t* item;
+ uv__cf_loop_signal_t* s;
+
+ assert(loop->cf_loop != NULL);
+ uv__cf_loop_signal(loop, NULL, NULL);
+ uv_thread_join(&loop->cf_thread);
+
+ 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);
+ }
+}
+
+
+static void uv__cf_loop_runner(void* arg) {
+ uv_loop_t* loop;
+
+ loop = arg;
+
+ /* Get thread's loop */
+ ACCESS_ONCE(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);
+}
+
+
+static 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);
+
+ /* This was a termination signal */
+ if (s->cb == NULL)
+ CFRunLoopStop(loop->cf_loop);
+ else
+ 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
index 7636b80cec..b6d274675a 100644
--- a/deps/uv/src/unix/fsevents.c
+++ b/deps/uv/src/unix/fsevents.c
@@ -34,149 +34,112 @@ int uv__fsevents_close(uv_fs_event_t* handle) {
return 0;
}
-
-void uv__fsevents_loop_delete(uv_loop_t* loop) {
- return 0;
-}
-
#else /* TARGET_OS_IPHONE */
#include <assert.h>
#include <stdlib.h>
-#include <CoreFoundation/CFRunLoop.h>
#include <CoreServices/CoreServices.h>
-/* These are macros to avoid "initializer element is not constant" errors
- * with old versions of gcc.
- */
-#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
- kFSEventStreamEventFlagItemModified | \
- kFSEventStreamEventFlagItemInodeMetaMod | \
- kFSEventStreamEventFlagItemChangeOwner | \
- kFSEventStreamEventFlagItemXattrMod)
-
-#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
- kFSEventStreamEventFlagItemRemoved | \
- kFSEventStreamEventFlagItemRenamed)
-
-#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
- kFSEventStreamEventFlagKernelDropped | \
- kFSEventStreamEventFlagEventIdsWrapped | \
- kFSEventStreamEventFlagHistoryDone | \
- kFSEventStreamEventFlagMount | \
- kFSEventStreamEventFlagUnmount | \
- kFSEventStreamEventFlagRootChanged)
-
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
-typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
-typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
-
-struct uv__cf_loop_state_s {
- CFRunLoopRef loop;
- CFRunLoopSourceRef signal_source;
- volatile int fsevent_need_reschedule;
- FSEventStreamRef fsevent_stream;
- uv_sem_t fsevent_sem;
- uv_mutex_t fsevent_mutex;
- ngx_queue_t fsevent_handles;
- int fsevent_handle_count;
-};
-
-struct uv__cf_loop_signal_s {
- ngx_queue_t member;
- uv_fs_event_t* handle;
-};
struct uv__fsevents_event_s {
int events;
- void* next;
+ ngx_queue_t member;
char path[1];
};
-/* Forward declarations */
-static void uv__cf_loop_cb(void* arg);
-static void* uv__cf_loop_runner(void* arg);
-static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle);
-#define UV__FSEVENTS_PROCESS(handle, block) \
- do { \
+#define UV__FSEVENTS_WALK(handle, block) \
+ { \
+ ngx_queue_t* curr; \
+ ngx_queue_t split_head; \
uv__fsevents_event_t* event; \
- uv__fsevents_event_t* next; \
uv_mutex_lock(&(handle)->cf_mutex); \
- event = (handle)->cf_event; \
- (handle)->cf_event = NULL; \
+ 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 (event != NULL) { \
+ 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 (!uv__is_closing((handle))) \
+ if (((handle)->flags & (UV_CLOSING | UV_CLOSED)) == 0) \
block \
/* Free allocated data */ \
- next = event->next; \
free(event); \
- event = next; \
} \
- } while (0)
+ }
-/* Runs in UV loop's thread, when there're events to report to handle */
-static void uv__fsevents_cb(uv_async_t* cb, int status) {
+void uv__fsevents_cb(uv_async_t* cb, int status) {
uv_fs_event_t* handle;
handle = cb->data;
- UV__FSEVENTS_PROCESS(handle, {
+ UV__FSEVENTS_WALK(handle, {
if (handle->event_watcher.fd != -1)
handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
});
- if (!uv__is_closing(handle) && handle->event_watcher.fd == -1)
+ if ((handle->flags & (UV_CLOSING | UV_CLOSED)) == 0 &&
+ handle->event_watcher.fd == -1) {
uv__fsevents_close(handle);
+ }
}
-/* Runs in CF thread, when there're events in FSEventStream */
-static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
- void* info,
- size_t numEvents,
- void* eventPaths,
- const FSEventStreamEventFlags eventFlags[],
- const FSEventStreamEventId eventIds[]) {
+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;
char* path;
char* pos;
uv_fs_event_t* handle;
- ngx_queue_t* q;
- uv_loop_t* loop;
- uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
- uv__fsevents_event_t* tail;
-
- loop = info;
- state = loop->cf_state;
- assert(state != NULL);
+ ngx_queue_t add_list;
+ int kFSEventsModified;
+ int kFSEventsRenamed;
+
+ kFSEventsModified = kFSEventStreamEventFlagItemFinderInfoMod |
+ kFSEventStreamEventFlagItemModified |
+ kFSEventStreamEventFlagItemInodeMetaMod |
+ kFSEventStreamEventFlagItemChangeOwner |
+ kFSEventStreamEventFlagItemXattrMod;
+ kFSEventsRenamed = kFSEventStreamEventFlagItemCreated |
+ kFSEventStreamEventFlagItemRemoved |
+ kFSEventStreamEventFlagItemRenamed;
+
+ 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 |
+ kFSEventStreamEventFlagRootChanged)) {
+ continue;
+ }
- /* For each handle */
- ngx_queue_foreach(q, &state->fsevent_handles) {
- handle = ngx_queue_data(q, uv_fs_event_t, cf_member);
- tail = NULL;
-
- /* Process and filter out events */
- for (i = 0; i < numEvents; i++) {
- /* Ignore system events */
- if (eventFlags[i] & kFSEventsSystem)
- continue;
-
- path = paths[i];
- len = strlen(path);
-
- /* Filter out paths that are outside handle's request */
- if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
- continue;
+ /* TODO: Report errors */
+ path = paths[i];
+ len = strlen(path);
+ /* Remove absolute path prefix */
+ if (strstr(path, handle->realpath) == path) {
path += handle->realpath_len;
len -= handle->realpath_len;
@@ -185,81 +148,91 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
path++;
len--;
}
+ }
#ifdef MAC_OS_X_VERSION_10_7
- /* Ignore events with path equal to directory itself */
- if (len == 0)
- continue;
+ /* Ignore events with path equal to directory itself */
+ if (len == 0)
+ continue;
#endif /* MAC_OS_X_VERSION_10_7 */
- /* Do not emit events from subdirectories (without option set) */
- if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0) {
- pos = strchr(path, '/');
- if (pos != NULL && pos != path + 1)
- continue;
- }
+ /* Do not emit events from subdirectories (without option set) */
+ pos = strchr(path, '/');
+ if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 &&
+ pos != NULL &&
+ pos != path + 1)
+ continue;
#ifndef MAC_OS_X_VERSION_10_7
- path = "";
- len = 0;
+ path = "";
+ len = 0;
#endif /* MAC_OS_X_VERSION_10_7 */
- event = malloc(sizeof(*event) + len);
- if (event == NULL)
- break;
+ event = malloc(sizeof(*event) + len);
+ if (event == NULL)
+ break;
- memset(event, 0, sizeof(*event));
- memcpy(event->path, path, len + 1);
+ memcpy(event->path, path, len + 1);
- if ((eventFlags[i] & kFSEventsModified) != 0 &&
- (eventFlags[i] & kFSEventsRenamed) == 0)
- event->events = UV_CHANGE;
- else
- event->events = UV_RENAME;
+ if ((eventFlags[i] & kFSEventsModified) != 0 &&
+ (eventFlags[i] & kFSEventsRenamed) == 0)
+ event->events = UV_CHANGE;
+ else
+ event->events = UV_RENAME;
- if (tail != NULL)
- tail->next = event;
- tail = event;
- }
+ 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);
- if (tail != NULL) {
- uv_mutex_lock(&handle->cf_mutex);
- tail->next = handle->cf_event;
- handle->cf_event = tail;
- uv_mutex_unlock(&handle->cf_mutex);
+ uv_async_send(handle->cf_cb);
+}
- 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);
}
-/* Runs in CF thread */
-static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
- uv__cf_loop_state_t* state;
+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 = loop;
+ ctx.info = handle;
ctx.retain = NULL;
ctx.release = NULL;
ctx.copyDescription = NULL;
+ /* Get absolute path to file */
+ handle->realpath = realpath(handle->filename, NULL);
+ if (handle->realpath != NULL)
+ handle->realpath_len = strlen(handle->realpath);
+
+ /* 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;
- /*
- * NOTE: It might sound like a good idea to remember last seen StreamEventId,
- * but in reality one dir might have last StreamEventId less than, the other,
- * that is being watched now. Which will cause FSEventStream API to report
- * changes to files from the past.
- */
ref = FSEventStreamCreate(NULL,
&uv__fsevents_event_cb,
&ctx,
@@ -267,419 +240,55 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
kFSEventStreamEventIdSinceNow,
latency,
flags);
- assert(ref != NULL);
-
- state = loop->cf_state;
- FSEventStreamScheduleWithRunLoop(ref,
- state->loop,
- kCFRunLoopDefaultMode);
- if (!FSEventStreamStart(ref))
- abort();
-
- state->fsevent_stream = ref;
-}
-
-
-/* Runs in CF thread */
-static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
- uv__cf_loop_state_t* state;
-
- state = loop->cf_state;
-
- if (state->fsevent_stream == NULL)
- return;
-
- /* Flush all accumulated events */
- FSEventStreamFlushSync(state->fsevent_stream);
-
- /* Stop emitting events */
- FSEventStreamStop(state->fsevent_stream);
-
- /* Release stream */
- FSEventStreamInvalidate(state->fsevent_stream);
- FSEventStreamRelease(state->fsevent_stream);
- state->fsevent_stream = NULL;
-}
-
-
-/* Runs in CF thread, when there're new fsevent handles to add to stream */
-static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
- uv__cf_loop_state_t* state;
- ngx_queue_t* q;
- uv_fs_event_t* curr;
- CFArrayRef cf_paths;
- CFStringRef* paths;
- int i;
- int path_count;
-
- state = handle->loop->cf_state;
-
- /* Optimization to prevent O(n^2) time spent when starting to watch
- * many files simultaneously
- */
- if (!state->fsevent_need_reschedule)
- return;
- state->fsevent_need_reschedule = 0;
-
- /* Destroy previous FSEventStream */
- uv__fsevents_destroy_stream(handle->loop);
-
- /* Create list of all watched paths */
- uv_mutex_lock(&state->fsevent_mutex);
- path_count = state->fsevent_handle_count;
- if (path_count != 0) {
- paths = malloc(sizeof(*paths) * path_count);
- if (paths == NULL)
- abort();
-
- q = &state->fsevent_handles;
- for (i = 0; i < path_count; i++) {
- q = ngx_queue_next(q);
- assert(q != &state->fsevent_handles);
- curr = ngx_queue_data(q, uv_fs_event_t, cf_member);
-
- assert(curr->realpath != NULL);
- paths[i] = CFStringCreateWithCString(NULL,
- curr->realpath,
- CFStringGetSystemEncoding());
- if (paths[i] == NULL)
- abort();
- }
- }
- uv_mutex_unlock(&state->fsevent_mutex);
-
- if (path_count != 0) {
- /* Create new FSEventStream */
- cf_paths = CFArrayCreate(NULL, (const void**) paths, path_count, NULL);
- if (cf_paths == NULL)
- abort();
- uv__fsevents_create_stream(handle->loop, cf_paths);
- }
-
- /*
- * Main thread will block until the removal of handle from the list,
- * we must tell it when we're ready.
- *
- * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
- */
- if (uv__is_closing(handle))
- uv_sem_post(&state->fsevent_sem);
-}
-
-
-/* Runs in UV loop */
-static int uv__fsevents_loop_init(uv_loop_t* loop) {
- CFRunLoopSourceContext ctx;
- uv__cf_loop_state_t* state;
- pthread_attr_t attr_storage;
- pthread_attr_t* attr;
- int err;
-
- if (loop->cf_state != NULL)
- return 0;
-
- state = calloc(1, sizeof(*state));
- if (state == NULL)
- return -ENOMEM;
-
- err = uv_mutex_init(&loop->cf_mutex);
- if (err)
- return err;
-
- err = uv_sem_init(&loop->cf_sem, 0);
- if (err)
- goto fail_sem_init;
-
- ngx_queue_init(&loop->cf_signals);
-
- err = uv_sem_init(&state->fsevent_sem, 0);
- if (err)
- goto fail_fsevent_sem_init;
-
- err = uv_mutex_init(&state->fsevent_mutex);
- if (err)
- goto fail_fsevent_mutex_init;
-
- ngx_queue_init(&state->fsevent_handles);
- state->fsevent_need_reschedule = 0;
- state->fsevent_handle_count = 0;
-
- memset(&ctx, 0, sizeof(ctx));
- ctx.info = loop;
- ctx.perform = uv__cf_loop_cb;
- state->signal_source = CFRunLoopSourceCreate(NULL, 0, &ctx);
- if (state->signal_source == NULL) {
- err = -ENOMEM;
- goto fail_signal_source_create;
- }
-
- /* In the unlikely event that pthread_attr_init() fails, create the thread
- * with the default stack size. We'll use a little more address space but
- * that in itself is not a fatal error.
- */
- attr = &attr_storage;
- if (pthread_attr_init(attr))
- attr = NULL;
-
- if (attr != NULL)
- if (pthread_attr_setstacksize(attr, 3 * PTHREAD_STACK_MIN))
- abort();
-
- loop->cf_state = state;
-
- /* uv_thread_t is an alias for pthread_t. */
- err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop);
-
- if (attr != NULL)
- pthread_attr_destroy(attr);
-
- if (err)
- goto fail_thread_create;
-
- /* Synchronize threads */
- uv_sem_wait(&loop->cf_sem);
- return 0;
-
-fail_thread_create:
- loop->cf_state = NULL;
-
-fail_signal_source_create:
- uv_mutex_destroy(&state->fsevent_mutex);
-
-fail_fsevent_mutex_init:
- uv_sem_destroy(&state->fsevent_sem);
-
-fail_fsevent_sem_init:
- uv_sem_destroy(&loop->cf_sem);
-
-fail_sem_init:
- uv_mutex_destroy(&loop->cf_mutex);
- free(state);
- return err;
-}
-
-
-/* Runs in UV loop */
-void uv__fsevents_loop_delete(uv_loop_t* loop) {
- uv__cf_loop_signal_t* s;
- uv__cf_loop_state_t* state;
- ngx_queue_t* q;
-
- if (loop->cf_state == NULL)
- return;
-
- if (uv__cf_loop_signal(loop, NULL) != 0)
- abort();
-
- uv_thread_join(&loop->cf_thread);
- uv_sem_destroy(&loop->cf_sem);
- uv_mutex_destroy(&loop->cf_mutex);
-
- /* Free any remaining data */
- while (!ngx_queue_empty(&loop->cf_signals)) {
- q = ngx_queue_head(&loop->cf_signals);
- s = ngx_queue_data(q, uv__cf_loop_signal_t, member);
- ngx_queue_remove(q);
- free(s);
- }
-
- /* Destroy state */
- state = loop->cf_state;
- uv_sem_destroy(&state->fsevent_sem);
- uv_mutex_destroy(&state->fsevent_mutex);
- CFRelease(state->signal_source);
- free(state);
- loop->cf_state = NULL;
-}
-
-
-/* Runs in CF thread. This is the CF loop's body */
-static void* uv__cf_loop_runner(void* arg) {
- uv_loop_t* loop;
- uv__cf_loop_state_t* state;
-
- loop = arg;
- state = loop->cf_state;
- state->loop = CFRunLoopGetCurrent();
-
- CFRunLoopAddSource(state->loop,
- state->signal_source,
- kCFRunLoopDefaultMode);
-
- uv_sem_post(&loop->cf_sem);
-
- CFRunLoopRun();
- CFRunLoopRemoveSource(state->loop,
- state->signal_source,
- kCFRunLoopDefaultMode);
-
- return NULL;
-}
-
-
-/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
-static void uv__cf_loop_cb(void* arg) {
- uv_loop_t* loop;
- uv__cf_loop_state_t* state;
- ngx_queue_t* item;
- ngx_queue_t split_head;
- uv__cf_loop_signal_t* s;
-
- loop = arg;
- state = loop->cf_state;
- ngx_queue_init(&split_head);
-
- uv_mutex_lock(&loop->cf_mutex);
- if (!ngx_queue_empty(&loop->cf_signals)) {
- ngx_queue_t* split_pos = ngx_queue_head(&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);
-
- /* This was a termination signal */
- if (s->handle == NULL)
- CFRunLoopStop(state->loop);
- else
- uv__fsevents_reschedule(s->handle);
-
- ngx_queue_remove(item);
- free(s);
- }
-}
-
-
-/* Runs in UV loop to notify CF thread */
-int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) {
- uv__cf_loop_signal_t* item;
- uv__cf_loop_state_t* state;
-
- item = malloc(sizeof(*item));
- if (item == NULL)
- return -ENOMEM;
-
- item->handle = handle;
-
- uv_mutex_lock(&loop->cf_mutex);
- ngx_queue_insert_tail(&loop->cf_signals, &item->member);
- uv_mutex_unlock(&loop->cf_mutex);
-
- state = loop->cf_state;
- assert(state != NULL);
- CFRunLoopSourceSignal(state->signal_source);
- CFRunLoopWakeUp(state->loop);
-
- return 0;
-}
-
-
-/* Runs in UV loop to initialize handle */
-int uv__fsevents_init(uv_fs_event_t* handle) {
- int err;
- uv__cf_loop_state_t* state;
-
- err = uv__fsevents_loop_init(handle->loop);
- if (err)
- return err;
-
- /* Get absolute path to file */
- handle->realpath = realpath(handle->filename, NULL);
- if (handle->realpath == NULL)
- return -errno;
- handle->realpath_len = strlen(handle->realpath);
-
- /* Initialize singly-linked list */
- handle->cf_event = NULL;
+ 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) {
- err = uv__set_sys_error(handle->loop, ENOMEM);
- goto fail_cf_cb_malloc;
- }
+ 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);
- err = uv_mutex_init(&handle->cf_mutex);
- if (err)
- goto fail_cf_mutex_init;
+ uv_mutex_init(&handle->cf_mutex);
+ uv_sem_init(&handle->cf_sem, 0);
+ ngx_queue_init(&handle->cf_events);
- /* Insert handle into the list */
- state = handle->loop->cf_state;
- uv_mutex_lock(&state->fsevent_mutex);
- ngx_queue_insert_tail(&state->fsevent_handles, &handle->cf_member);
- state->fsevent_handle_count++;
- state->fsevent_need_reschedule = 1;
- uv_mutex_unlock(&state->fsevent_mutex);
-
- /* Reschedule FSEventStream */
- assert(handle != NULL);
- err = uv__cf_loop_signal(handle->loop, handle);
- if (err)
- goto fail_loop_signal;
+ uv__cf_loop_signal(handle->loop, uv__fsevents_schedule, handle);
return 0;
-
-fail_loop_signal:
- uv_mutex_destroy(&handle->cf_mutex);
-
-fail_cf_mutex_init:
- free(handle->cf_cb);
- handle->cf_cb = NULL;
-
-fail_cf_cb_malloc:
- free(handle->realpath);
- handle->realpath = NULL;
- handle->realpath_len = 0;
-
- return err;
}
-/* Runs in UV loop to de-initialize handle */
int uv__fsevents_close(uv_fs_event_t* handle) {
- int err;
- uv__cf_loop_state_t* state;
+ if (handle->cf_eventstream == NULL)
+ return -1;
- if (handle->cf_cb == NULL)
- return -EINVAL;
+ /* Ensure that event stream was scheduled */
+ uv_sem_wait(&handle->cf_sem);
- /* Remove handle from the list */
- state = handle->loop->cf_state;
- uv_mutex_lock(&state->fsevent_mutex);
- ngx_queue_remove(&handle->cf_member);
- state->fsevent_handle_count--;
- state->fsevent_need_reschedule = 1;
- uv_mutex_unlock(&state->fsevent_mutex);
-
- /* Reschedule FSEventStream */
- assert(handle != NULL);
- err = uv__cf_loop_signal(handle->loop, handle);
- if (err)
- return -err;
+ /* Stop emitting events */
+ FSEventStreamStop(handle->cf_eventstream);
- /* Wait for deinitialization */
- uv_sem_wait(&state->fsevent_sem);
+ /* 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);
- handle->cf_cb = NULL;
/* Free data in queue */
- UV__FSEVENTS_PROCESS(handle, {
+ UV__FSEVENTS_WALK(handle, {
/* NOP */
- });
+ })
uv_mutex_destroy(&handle->cf_mutex);
+ uv_sem_destroy(&handle->cf_sem);
free(handle->realpath);
handle->realpath = NULL;
handle->realpath_len = 0;
diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h
index 2bb4dc1b04..61cb1ec1f0 100644
--- a/deps/uv/src/unix/internal.h
+++ b/deps/uv/src/unix/internal.h
@@ -216,10 +216,12 @@ 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);
-void uv__fsevents_loop_delete(uv_loop_t* loop);
/* OSX < 10.7 has no file events, polyfill them */
#ifndef MAC_OS_X_VERSION_10_7
diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c
index a46c88f4bf..378903a627 100644
--- a/deps/uv/src/unix/kqueue.c
+++ b/deps/uv/src/unix/kqueue.c
@@ -307,7 +307,7 @@ int uv_fs_event_init(uv_loop_t* loop,
#if defined(__APPLE__)
/* Nullify field to perform checks later */
- handle->cf_cb = NULL;
+ handle->cf_eventstream = NULL;
handle->realpath = NULL;
handle->realpath_len = 0;
handle->cf_flags = flags;
diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c
index 7ef84d0d2a..389817f211 100644
--- a/deps/uv/src/unix/process.c
+++ b/deps/uv/src/unix/process.c
@@ -186,7 +186,7 @@ skip:
/*
* Used for initializing stdio streams like options.stdin_stream. Returns
- * zero on success.
+ * zero on success. See also the cleanup section in uv_spawn().
*/
static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
int mask;
@@ -463,11 +463,18 @@ int uv_spawn(uv_loop_t* loop,
error:
uv__set_sys_error(process->loop, errno);
- for (i = 0; i < stdio_count; i++) {
- close(pipes[i][0]);
- close(pipes[i][1]);
+ if (pipes != NULL) {
+ for (i = 0; i < stdio_count; i++) {
+ if (i < options.stdio_count)
+ if (options.stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
+ continue;
+ if (pipes[i][0] != -1)
+ close(pipes[i][0]);
+ if (pipes[i][1] != -1)
+ close(pipes[i][1]);
+ }
+ free(pipes);
}
- free(pipes);
return -1;
}
diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c
index 22c7783b9f..aa84ff2f2d 100644
--- a/deps/uv/src/unix/signal.c
+++ b/deps/uv/src/unix/signal.c
@@ -141,7 +141,10 @@ static void uv__signal_handler(int signum) {
saved_errno = errno;
memset(&msg, 0, sizeof msg);
- uv__signal_lock();
+ if (uv__signal_lock()) {
+ errno = saved_errno;
+ return;
+ }
for (handle = uv__signal_first_handle(signum);
handle != NULL && handle->signum == signum;
diff --git a/deps/uv/src/version.c b/deps/uv/src/version.c
index 5489601795..e272d5f4c3 100644
--- a/deps/uv/src/version.c
+++ b/deps/uv/src/version.c
@@ -34,7 +34,7 @@
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 10
-#define UV_VERSION_PATCH 17
+#define UV_VERSION_PATCH 18
#define UV_VERSION_IS_RELEASE 1