From 8fc48bcf4ca49f16b910b388481030870f78665f Mon Sep 17 00:00:00 2001 From: Timothy J Fontaine Date: Fri, 18 Oct 2013 13:52:15 -0700 Subject: [PATCH] uv: Upgrade to v0.10.18 --- deps/uv/ChangeLog | 15 +- deps/uv/include/uv-private/uv-darwin.h | 10 +- deps/uv/src/unix/darwin.c | 131 ++++++- deps/uv/src/unix/fsevents.c | 655 +++++++-------------------------- deps/uv/src/unix/internal.h | 4 +- deps/uv/src/unix/kqueue.c | 2 +- deps/uv/src/unix/process.c | 17 +- deps/uv/src/unix/signal.c | 5 +- deps/uv/src/version.c | 2 +- 9 files changed, 301 insertions(+), 540 deletions(-) diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 98fb44f..794764e 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 4037f5c..e861cba 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 08da513..77e662f 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -28,6 +28,8 @@ #include #include +#include + #include #include #include /* _NSGetExecutablePath */ @@ -35,19 +37,144 @@ #include #include /* 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 7636b80..b6d2746 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 #include -#include #include -/* 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 2bb4dc1..61cb1ec 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 a46c88f..378903a 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 7ef84d0..389817f 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 22c7783..aa84ff2 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 5489601..e272d5f 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 -- 2.7.4