summaryrefslogtreecommitdiff
path: root/deps/uv/src/unix/fsevents.c
diff options
context:
space:
mode:
authorTimothy J Fontaine <tjfontaine@gmail.com>2013-08-21 11:15:21 -0700
committerTimothy J Fontaine <tjfontaine@gmail.com>2013-08-21 11:15:21 -0700
commita784abaff631449533d44846987c1537c080e03d (patch)
tree0982d9a92450edb9e46ba683d75eb7822ea004b3 /deps/uv/src/unix/fsevents.c
parent41f55dc59b423b8b76e6f7971fd8f3a326a6fbad (diff)
downloadandroid-node-v8-a784abaff631449533d44846987c1537c080e03d.tar.gz
android-node-v8-a784abaff631449533d44846987c1537c080e03d.tar.bz2
android-node-v8-a784abaff631449533d44846987c1537c080e03d.zip
uv: Upgrade to v0.11.8
Diffstat (limited to 'deps/uv/src/unix/fsevents.c')
-rw-r--r--deps/uv/src/unix/fsevents.c267
1 files changed, 233 insertions, 34 deletions
diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c
index ef9a352b7f..79ad198bae 100644
--- a/deps/uv/src/unix/fsevents.c
+++ b/deps/uv/src/unix/fsevents.c
@@ -34,13 +34,28 @@ int uv__fsevents_close(uv_fs_event_t* handle) {
return 0;
}
+
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+}
+
#else /* TARGET_OS_IPHONE */
#include <assert.h>
#include <stdlib.h>
+#include <pthread.h>
+
+#include <CoreFoundation/CFRunLoop.h>
#include <CoreServices/CoreServices.h>
typedef struct uv__fsevents_event_s uv__fsevents_event_t;
+typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
+typedef void (*cf_loop_signal_cb)(void* arg);
+
+struct uv__cf_loop_signal_s {
+ cf_loop_signal_cb cb;
+ QUEUE member;
+ void* arg;
+};
struct uv__fsevents_event_s {
int events;
@@ -48,6 +63,12 @@ struct uv__fsevents_event_s {
char path[1];
};
+/* Forward declarations */
+static void uv__cf_loop_cb(void* arg);
+static void* uv__cf_loop_runner(void* arg);
+static void uv__cf_loop_signal(uv_loop_t* loop,
+ cf_loop_signal_cb cb,
+ void* arg);
#define UV__FSEVENTS_WALK(handle, block) \
{ \
@@ -75,7 +96,7 @@ struct uv__fsevents_event_s {
}
-void uv__fsevents_cb(uv_async_t* cb, int status) {
+static void uv__fsevents_cb(uv_async_t* cb, int status) {
uv_fs_event_t* handle;
handle = cb->data;
@@ -92,12 +113,12 @@ void uv__fsevents_cb(uv_async_t* cb, int status) {
}
-void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
- void* info,
- size_t numEvents,
- void* eventPaths,
- const FSEventStreamEventFlags eventFlags[],
- const FSEventStreamEventId eventIds[]) {
+static 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;
@@ -190,19 +211,8 @@ void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
}
-void uv__fsevents_schedule(void* arg) {
+static 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;
@@ -210,6 +220,8 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
CFAbsoluteTime latency;
FSEventStreamCreateFlags flags;
+ handle = arg;
+
/* Initialize context */
ctx.version = 0;
ctx.info = handle;
@@ -217,16 +229,13 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
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());
+ assert(path != NULL);
paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL);
+ assert(paths != NULL);
latency = 0.15;
@@ -240,8 +249,203 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
kFSEventStreamEventIdSinceNow,
latency,
flags);
+ assert(ref != NULL);
handle->cf_eventstream = ref;
+ FSEventStreamScheduleWithRunLoop(handle->cf_eventstream,
+ handle->loop->cf_loop,
+ kCFRunLoopDefaultMode);
+ if (!FSEventStreamStart(handle->cf_eventstream))
+ abort();
+}
+
+
+static void uv__fsevents_unschedule(void* arg) {
+ uv_fs_event_t* handle;
+
+ handle = arg;
+
+ /* Stop emitting events */
+ FSEventStreamStop(handle->cf_eventstream);
+
+ /* Release stream */
+ FSEventStreamInvalidate(handle->cf_eventstream);
+ FSEventStreamRelease(handle->cf_eventstream);
+ handle->cf_eventstream = NULL;
+
+ /* Notify main thread that we're done here */
+ uv_sem_post(&handle->cf_sem);
+}
+
+
+static int uv__fsevents_loop_init(uv_loop_t* loop) {
+ CFRunLoopSourceContext ctx;
+ pthread_attr_t attr_storage;
+ pthread_attr_t* attr;
+ int err;
+
+ if (loop->cf_loop != NULL)
+ return 0;
+
+ 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;
+
+ 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);
+
+ /* 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();
+
+ /* 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);
+ assert(loop->cf_loop != NULL);
+ return 0;
+
+fail_thread_create:
+ uv_sem_destroy(&loop->cf_sem);
+
+fail_sem_init:
+ uv_mutex_destroy(&loop->cf_mutex);
+ return err;
+}
+
+
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+ uv__cf_loop_signal_t* s;
+ QUEUE* q;
+
+ if (loop->cf_loop == NULL)
+ return;
+
+ 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 (!QUEUE_EMPTY(&loop->cf_signals)) {
+ q = QUEUE_HEAD(&loop->cf_signals);
+ s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
+ QUEUE_REMOVE(q);
+ free(s);
+ }
+}
+
+
+static void* uv__cf_loop_runner(void* arg) {
+ uv_loop_t* loop;
+
+ loop = arg;
+ 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);
+
+ return NULL;
+}
+
+
+static void uv__cf_loop_cb(void* arg) {
+ uv_loop_t* loop;
+ QUEUE* item;
+ QUEUE split_head;
+ uv__cf_loop_signal_t* s;
+
+ loop = arg;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_INIT(&split_head);
+ if (!QUEUE_EMPTY(&loop->cf_signals)) {
+ QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals);
+ QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head);
+ }
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ while (!QUEUE_EMPTY(&split_head)) {
+ item = QUEUE_HEAD(&split_head);
+
+ s = 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);
+
+ 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);
+ 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);
+}
+
+
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ int err;
+
+ 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)
+ handle->realpath_len = strlen(handle->realpath);
+
+ handle->cf_eventstream = NULL;
/*
* Events will occur in other thread.
* Initialize callback for getting them back into event loop's thread
@@ -266,21 +470,16 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
int uv__fsevents_close(uv_fs_event_t* handle) {
- if (handle->cf_eventstream == NULL)
+ if (handle->cf_cb == NULL)
return -EINVAL;
- /* Ensure that event stream was scheduled */
- uv_sem_wait(&handle->cf_sem);
-
- /* Stop emitting events */
- FSEventStreamStop(handle->cf_eventstream);
+ uv__cf_loop_signal(handle->loop, uv__fsevents_unschedule, handle);
- /* Release stream */
- FSEventStreamInvalidate(handle->cf_eventstream);
- FSEventStreamRelease(handle->cf_eventstream);
- handle->cf_eventstream = NULL;
+ /* Wait for deinitialization */
+ uv_sem_wait(&handle->cf_sem);
uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) free);
+ handle->cf_cb = NULL;
/* Free data in queue */
UV__FSEVENTS_WALK(handle, {