summaryrefslogtreecommitdiff
path: root/deps/uv/src/unix/fsevents.c
diff options
context:
space:
mode:
authorTimothy J Fontaine <tjfontaine@gmail.com>2013-11-20 08:25:24 -0800
committerTimothy J Fontaine <tjfontaine@gmail.com>2013-11-20 09:35:08 -0800
commit1fef66ffd4cf302fec7be1e2fd86f209cf1ff0d3 (patch)
tree414aeb957641dd121f529ebefeab15286826ca5f /deps/uv/src/unix/fsevents.c
parentaef652dc111bef8dc970353243ba8ce2c23f014e (diff)
downloadandroid-node-v8-1fef66ffd4cf302fec7be1e2fd86f209cf1ff0d3.tar.gz
android-node-v8-1fef66ffd4cf302fec7be1e2fd86f209cf1ff0d3.tar.bz2
android-node-v8-1fef66ffd4cf302fec7be1e2fd86f209cf1ff0d3.zip
uv: upgrade to v0.11.15
Diffstat (limited to 'deps/uv/src/unix/fsevents.c')
-rw-r--r--deps/uv/src/unix/fsevents.c203
1 files changed, 139 insertions, 64 deletions
diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c
index 305de6def0..3618f46996 100644
--- a/deps/uv/src/unix/fsevents.c
+++ b/deps/uv/src/unix/fsevents.c
@@ -73,28 +73,28 @@ 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;
- int fsevent_need_reschedule;
- FSEventStreamRef fsevent_stream;
- uv_sem_t fsevent_sem;
- uv_mutex_t fsevent_mutex;
- void* fsevent_handles[2];
- int fsevent_handle_count;
-};
-
struct uv__cf_loop_signal_s {
QUEUE member;
uv_fs_event_t* handle;
};
struct uv__fsevents_event_s {
+ QUEUE member;
int events;
- void* next;
char path[1];
};
+struct uv__cf_loop_state_s {
+ CFRunLoopRef loop;
+ CFRunLoopSourceRef signal_source;
+ int fsevent_need_reschedule;
+ FSEventStreamRef fsevent_stream;
+ uv_sem_t fsevent_sem;
+ uv_mutex_t fsevent_mutex;
+ void* fsevent_handles[2];
+ unsigned int fsevent_handle_count;
+};
+
/* Forward declarations */
static void uv__cf_loop_cb(void* arg);
static void* uv__cf_loop_runner(void* arg);
@@ -120,9 +120,9 @@ static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
static void (*pCFRunLoopStop)(CFRunLoopRef);
static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
-static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
- const char*,
- CFStringEncoding);
+static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
+ CFAllocatorRef,
+ const char*);
static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
static CFStringRef (*pkCFRunLoopDefaultMode);
static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
@@ -143,22 +143,36 @@ static void (*pFSEventStreamStop)(FSEventStreamRef);
#define UV__FSEVENTS_PROCESS(handle, block) \
do { \
+ QUEUE events; \
+ QUEUE* q; \
uv__fsevents_event_t* event; \
- uv__fsevents_event_t* next; \
+ int err; \
uv_mutex_lock(&(handle)->cf_mutex); \
- event = (handle)->cf_event; \
- (handle)->cf_event = NULL; \
+ /* Split-off all events and empty original queue */ \
+ QUEUE_INIT(&events); \
+ if (!QUEUE_EMPTY(&(handle)->cf_events)) { \
+ q = QUEUE_HEAD(&(handle)->cf_events); \
+ QUEUE_SPLIT(&(handle)->cf_events, q, &events); \
+ } \
+ /* Get error (if any) and zero original one */ \
+ err = (handle)->cf_error; \
+ (handle)->cf_error = 0; \
uv_mutex_unlock(&(handle)->cf_mutex); \
- while (event != NULL) { \
- /* Invoke callback */ \
- /* Invoke block code, but only if handle wasn't closed */ \
- if (!uv__is_closing((handle))) \
+ /* Loop through events, deallocating each after processing */ \
+ while (!QUEUE_EMPTY(&events)) { \
+ q = QUEUE_HEAD(&events); \
+ event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
+ QUEUE_REMOVE(q); \
+ /* NOTE: Checking uv__is_active() is required here, because handle \
+ * callback may close handle and invoking it after it will lead to \
+ * incorrect behaviour */ \
+ if (!uv__is_closing((handle)) && uv__is_active((handle))) \
block \
/* Free allocated data */ \
- next = event->next; \
free(event); \
- event = next; \
} \
+ if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
+ (handle)->cb((handle), NULL, 0, err); \
} while (0)
@@ -169,12 +183,28 @@ static void uv__fsevents_cb(uv_async_t* cb, int status) {
handle = cb->data;
UV__FSEVENTS_PROCESS(handle, {
- if (handle->event_watcher.fd != -1)
- handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
+ handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
});
+}
+
+
+/* Runs in CF thread, pushed event into handle's event list */
+static void uv__fsevents_push_event(uv_fs_event_t* handle,
+ QUEUE* events,
+ int err) {
+ assert(events != NULL || err != 0);
+ uv_mutex_lock(&handle->cf_mutex);
+
+ /* Concatenate two queues */
+ if (events != NULL)
+ QUEUE_ADD(&handle->cf_events, events);
- if (!uv__is_closing(handle) && handle->event_watcher.fd == -1)
- uv__fsevents_close(handle);
+ /* Propagate error */
+ if (err != 0)
+ handle->cf_error = err;
+ uv_mutex_unlock(&handle->cf_mutex);
+
+ uv_async_send(handle->cf_cb);
}
@@ -195,7 +225,7 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
uv_loop_t* loop;
uv__cf_loop_state_t* state;
uv__fsevents_event_t* event;
- uv__fsevents_event_t* tail;
+ QUEUE head;
loop = info;
state = loop->cf_state;
@@ -203,9 +233,10 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
paths = eventPaths;
/* For each handle */
+ uv_mutex_lock(&state->fsevent_mutex);
QUEUE_FOREACH(q, &state->fsevent_handles) {
handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
- tail = NULL;
+ QUEUE_INIT(&head);
/* Process and filter out events */
for (i = 0; i < numEvents; i++) {
@@ -260,25 +291,18 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
else
event->events = UV_RENAME;
- if (tail != NULL)
- tail->next = event;
- tail = event;
+ QUEUE_INSERT_TAIL(&head, &event->member);
}
- 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);
- }
+ if (!QUEUE_EMPTY(&head))
+ uv__fsevents_push_event(handle, &head, 0);
}
+ uv_mutex_unlock(&state->fsevent_mutex);
}
/* Runs in CF thread */
-static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
+static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
uv__cf_loop_state_t* state;
FSEventStreamContext ctx;
FSEventStreamRef ref;
@@ -292,10 +316,21 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
ctx.release = NULL;
ctx.copyDescription = NULL;
- latency = 0.15;
-
- /* Set appropriate flags */
- flags = kFSEventStreamCreateFlagFileEvents;
+ latency = 0.05;
+
+ /* Explanation of selected flags:
+ * 1. NoDefer - without this flag, events that are happening continuously
+ * (i.e. each event is happening after time interval less than `latency`,
+ * counted from previous event), will be deferred and passed to callback
+ * once they'll either fill whole OS buffer, or when this continuous stream
+ * will stop (i.e. there'll be delay between events, bigger than
+ * `latency`).
+ * Specifying this flag will invoke callback after `latency` time passed
+ * since event.
+ * 2. FileEvents - fire callback for file changes too (by default it is firing
+ * it only for directory changes).
+ */
+ flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
/*
* NOTE: It might sound like a good idea to remember last seen StreamEventId,
@@ -316,10 +351,14 @@ static void uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
pFSEventStreamScheduleWithRunLoop(ref,
state->loop,
*pkCFRunLoopDefaultMode);
- if (!pFSEventStreamStart(ref))
- abort();
+ if (!pFSEventStreamStart(ref)) {
+ pFSEventStreamInvalidate(ref);
+ pFSEventStreamRelease(ref);
+ return -EMFILE;
+ }
state->fsevent_stream = ref;
+ return 0;
}
@@ -352,10 +391,16 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
uv_fs_event_t* curr;
CFArrayRef cf_paths;
CFStringRef* paths;
- int i;
- int path_count;
+ unsigned int i;
+ int err;
+ unsigned int path_count;
state = handle->loop->cf_state;
+ paths = NULL;
+ cf_paths = NULL;
+ err = 0;
+ /* NOTE: `i` is used in deallocation loop below */
+ i = 0;
/* Optimization to prevent O(n^2) time spent when starting to watch
* many files simultaneously
@@ -371,39 +416,68 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) {
/* Destroy previous FSEventStream */
uv__fsevents_destroy_stream(handle->loop);
+ /* Any failure below will be a memory failure */
+ err = -ENOMEM;
+
/* 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();
+ if (paths == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
q = &state->fsevent_handles;
- for (i = 0; i < path_count; i++) {
+ for (; i < path_count; i++) {
q = QUEUE_NEXT(q);
assert(q != &state->fsevent_handles);
curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
assert(curr->realpath != NULL);
- paths[i] = pCFStringCreateWithCString(NULL,
- curr->realpath,
- pCFStringGetSystemEncoding());
- if (paths[i] == NULL)
- abort();
+ paths[i] =
+ pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
+ if (paths[i] == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
}
}
uv_mutex_unlock(&state->fsevent_mutex);
+ err = 0;
if (path_count != 0) {
/* Create new FSEventStream */
cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
- if (cf_paths == NULL)
- abort();
- uv__fsevents_create_stream(handle->loop, cf_paths);
+ if (cf_paths == NULL) {
+ err = -ENOMEM;
+ goto final;
+ }
+ err = uv__fsevents_create_stream(handle->loop, cf_paths);
}
final:
+ /* Deallocate all paths in case of failure */
+ if (err != 0) {
+ if (cf_paths == NULL) {
+ while (i != 0)
+ pCFRelease(paths[--i]);
+ free(paths);
+ } else {
+ /* CFArray takes ownership of both strings and original C-array */
+ pCFRelease(cf_paths);
+ }
+
+ /* Broadcast error to all handles */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ uv__fsevents_push_event(curr, NULL, err);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ }
+
/*
* Main thread will block until the removal of handle from the list,
* we must tell it when we're ready.
@@ -464,7 +538,7 @@ static int uv__fsevents_global_init(void) {
V(core_foundation_handle, CFRunLoopSourceSignal);
V(core_foundation_handle, CFRunLoopStop);
V(core_foundation_handle, CFRunLoopWakeUp);
- V(core_foundation_handle, CFStringCreateWithCString);
+ V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
V(core_foundation_handle, CFStringGetSystemEncoding);
V(core_foundation_handle, kCFRunLoopDefaultMode);
V(core_services_handle, FSEventStreamCreate);
@@ -722,8 +796,9 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
return -errno;
handle->realpath_len = strlen(handle->realpath);
- /* Initialize singly-linked list */
- handle->cf_event = NULL;
+ /* Initialize event queue */
+ QUEUE_INIT(&handle->cf_events);
+ handle->cf_error = 0;
/*
* Events will occur in other thread.