24 #if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
49 #include <CoreFoundation/CFRunLoop.h>
50 #include <CoreServices/CoreServices.h>
55 #define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
56 kFSEventStreamEventFlagItemModified | \
57 kFSEventStreamEventFlagItemInodeMetaMod | \
58 kFSEventStreamEventFlagItemChangeOwner | \
59 kFSEventStreamEventFlagItemXattrMod)
61 #define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
62 kFSEventStreamEventFlagItemRemoved | \
63 kFSEventStreamEventFlagItemRenamed)
65 #define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
66 kFSEventStreamEventFlagKernelDropped | \
67 kFSEventStreamEventFlagEventIdsWrapped | \
68 kFSEventStreamEventFlagHistoryDone | \
69 kFSEventStreamEventFlagMount | \
70 kFSEventStreamEventFlagUnmount | \
71 kFSEventStreamEventFlagRootChanged)
73 typedef struct uv__fsevents_event_s uv__fsevents_event_t;
74 typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
75 typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
77 enum uv__cf_loop_signal_type_e {
78 kUVCFLoopSignalRegular,
79 kUVCFLoopSignalClosing
81 typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
83 struct uv__cf_loop_signal_s {
86 uv__cf_loop_signal_type_t
type;
89 struct uv__fsevents_event_s {
95 struct uv__cf_loop_state_s {
97 CFRunLoopSourceRef signal_source;
98 int fsevent_need_reschedule;
99 FSEventStreamRef fsevent_stream;
102 void* fsevent_handles[2];
103 unsigned int fsevent_handle_count;
107 static void uv__cf_loop_cb(
void*
arg);
108 static void* uv__cf_loop_runner(
void*
arg);
111 uv__cf_loop_signal_type_t
type);
114 static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
117 const CFArrayCallBacks*);
118 static void (*pCFRelease)(CFTypeRef);
119 static void (*pCFRunLoopAddSource)(CFRunLoopRef,
122 static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
123 static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
126 static void (*pCFRunLoopRun)(void);
127 static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
129 CFRunLoopSourceContext*);
130 static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
131 static void (*pCFRunLoopStop)(CFRunLoopRef);
132 static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
133 static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
136 static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
137 static CFStringRef (*pkCFRunLoopDefaultMode);
138 static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
139 FSEventStreamCallback,
140 FSEventStreamContext*,
142 FSEventStreamEventId,
144 FSEventStreamCreateFlags);
145 static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
146 static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
147 static void (*pFSEventStreamRelease)(FSEventStreamRef);
148 static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
151 static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
152 static void (*pFSEventStreamStop)(FSEventStreamRef);
154 #define UV__FSEVENTS_PROCESS(handle, block) \
158 uv__fsevents_event_t* event; \
160 uv_mutex_lock(&(handle)->cf_mutex); \
162 QUEUE_MOVE(&(handle)->cf_events, &events); \
164 err = (handle)->cf_error; \
165 (handle)->cf_error = 0; \
166 uv_mutex_unlock(&(handle)->cf_mutex); \
168 while (!QUEUE_EMPTY(&events)) { \
169 q = QUEUE_HEAD(&events); \
170 event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
175 if (!uv__is_closing((handle)) && uv__is_active((handle))) \
180 if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
181 (handle)->cb((handle), NULL, 0, err); \
191 UV__FSEVENTS_PROCESS(
handle, {
192 handle->cb(
handle, event->path[0] ? event->path : NULL, event->events, 0);
201 assert(events != NULL ||
err != 0);
218 static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
222 const FSEventStreamEventFlags eventFlags[],
223 const FSEventStreamEventId eventIds[]) {
232 uv__cf_loop_state_t*
state;
233 uv__fsevents_event_t* event;
234 FSEventStreamEventFlags
flags;
239 assert(
state != NULL);
249 for (
i = 0;
i < numEvents;
i++) {
253 if (
flags & kFSEventsSystem)
259 if (
handle->realpath_len == 0)
263 if (len < handle->realpath_len)
270 handle->realpath_len > 1 &&
277 if (!(
handle->realpath_len == 1 &&
handle->realpath[0] ==
'/')) {
283 if (
len <= 1 && (
flags & kFSEventStreamEventFlagItemIsDir))
290 while (len < handle->realpath_len &&
path[-1] !=
'/') {
295 flags &= ~kFSEventsRenamed;
314 memset(event, 0,
sizeof(*event));
318 if (0 == (
flags & kFSEventsRenamed)) {
319 if (0 != (
flags & kFSEventsModified) ||
320 0 == (
flags & kFSEventStreamEventFlagItemIsDir))
328 uv__fsevents_push_event(
handle, &head, 0);
335 static int uv__fsevents_create_stream(
uv_loop_t*
loop, CFArrayRef paths) {
336 uv__cf_loop_state_t*
state;
337 FSEventStreamContext
ctx;
338 FSEventStreamRef
ref;
339 CFAbsoluteTime latency;
340 FSEventStreamCreateFlags
flags;
347 ctx.copyDescription = NULL;
363 flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
371 ref = pFSEventStreamCreate(NULL,
372 &uv__fsevents_event_cb,
375 kFSEventStreamEventIdSinceNow,
381 pFSEventStreamScheduleWithRunLoop(
ref,
383 *pkCFRunLoopDefaultMode);
384 if (!pFSEventStreamStart(
ref)) {
385 pFSEventStreamInvalidate(
ref);
386 pFSEventStreamRelease(
ref);
397 uv__cf_loop_state_t*
state;
401 if (
state->fsevent_stream == NULL)
405 pFSEventStreamStop(
state->fsevent_stream);
408 pFSEventStreamInvalidate(
state->fsevent_stream);
409 pFSEventStreamRelease(
state->fsevent_stream);
410 state->fsevent_stream = NULL;
416 uv__cf_loop_signal_type_t
type) {
417 uv__cf_loop_state_t*
state;
424 unsigned int path_count;
437 if (
state->fsevent_need_reschedule == 0) {
441 state->fsevent_need_reschedule = 0;
445 uv__fsevents_destroy_stream(
handle->loop);
452 path_count =
state->fsevent_handle_count;
453 if (path_count != 0) {
454 paths =
uv__malloc(
sizeof(*paths) * path_count);
460 q = &
state->fsevent_handles;
461 for (;
i < path_count;
i++) {
463 assert(q != &
state->fsevent_handles);
466 assert(curr->realpath != NULL);
468 pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
469 if (paths[
i] == NULL) {
478 if (path_count != 0) {
480 cf_paths = pCFArrayCreate(NULL, (
const void**) paths, path_count, NULL);
481 if (cf_paths == NULL) {
485 err = uv__fsevents_create_stream(
handle->loop, cf_paths);
491 if (cf_paths == NULL) {
493 pCFRelease(paths[--
i]);
497 pCFRelease(cf_paths);
504 uv__fsevents_push_event(curr, NULL,
err);
515 if (
type == kUVCFLoopSignalClosing)
520 static int uv__fsevents_global_init(
void) {
521 static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
522 static void* core_foundation_handle;
523 static void* core_services_handle;
527 pthread_mutex_lock(&global_init_mutex);
528 if (core_foundation_handle != NULL)
537 core_foundation_handle = dlopen(
"/System/Library/Frameworks/"
538 "CoreFoundation.framework/"
539 "Versions/A/CoreFoundation",
540 RTLD_LAZY | RTLD_LOCAL);
541 if (core_foundation_handle == NULL)
544 core_services_handle = dlopen(
"/System/Library/Frameworks/"
545 "CoreServices.framework/"
546 "Versions/A/CoreServices",
547 RTLD_LAZY | RTLD_LOCAL);
548 if (core_services_handle == NULL)
552 #define V(handle, symbol) \
554 *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
555 if (p ## symbol == NULL) \
559 V(core_foundation_handle, CFArrayCreate);
560 V(core_foundation_handle, CFRelease);
561 V(core_foundation_handle, CFRunLoopAddSource);
562 V(core_foundation_handle, CFRunLoopGetCurrent);
563 V(core_foundation_handle, CFRunLoopRemoveSource);
564 V(core_foundation_handle, CFRunLoopRun);
565 V(core_foundation_handle, CFRunLoopSourceCreate);
566 V(core_foundation_handle, CFRunLoopSourceSignal);
567 V(core_foundation_handle, CFRunLoopStop);
568 V(core_foundation_handle, CFRunLoopWakeUp);
569 V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
570 V(core_foundation_handle, CFStringGetSystemEncoding);
571 V(core_foundation_handle, kCFRunLoopDefaultMode);
572 V(core_services_handle, FSEventStreamCreate);
573 V(core_services_handle, FSEventStreamFlushSync);
574 V(core_services_handle, FSEventStreamInvalidate);
575 V(core_services_handle, FSEventStreamRelease);
576 V(core_services_handle, FSEventStreamScheduleWithRunLoop);
577 V(core_services_handle, FSEventStreamStart);
578 V(core_services_handle, FSEventStreamStop);
583 if (
err && core_services_handle != NULL) {
584 dlclose(core_services_handle);
585 core_services_handle = NULL;
588 if (
err && core_foundation_handle != NULL) {
589 dlclose(core_foundation_handle);
590 core_foundation_handle = NULL;
593 pthread_mutex_unlock(&global_init_mutex);
600 CFRunLoopSourceContext
ctx;
601 uv__cf_loop_state_t*
state;
602 pthread_attr_t attr_storage;
603 pthread_attr_t*
attr;
606 if (
loop->cf_state != NULL)
609 err = uv__fsevents_global_init();
619 goto fail_mutex_init;
629 goto fail_fsevent_sem_init;
633 goto fail_fsevent_mutex_init;
636 state->fsevent_need_reschedule = 0;
637 state->fsevent_handle_count = 0;
641 ctx.perform = uv__cf_loop_cb;
642 state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &
ctx);
643 if (
state->signal_source == NULL) {
645 goto fail_signal_source_create;
652 attr = &attr_storage;
653 if (pthread_attr_init(
attr))
657 if (pthread_attr_setstacksize(
attr, 4 * PTHREAD_STACK_MIN))
666 pthread_attr_destroy(
attr);
669 goto fail_thread_create;
676 loop->cf_state = NULL;
678 fail_signal_source_create:
681 fail_fsevent_mutex_init:
684 fail_fsevent_sem_init:
698 uv__cf_loop_signal_t*
s;
699 uv__cf_loop_state_t*
state;
702 if (
loop->cf_state == NULL)
705 if (uv__cf_loop_signal(
loop, NULL, kUVCFLoopSignalRegular) != 0)
724 pCFRelease(
state->signal_source);
726 loop->cf_state = NULL;
731 static void* uv__cf_loop_runner(
void*
arg) {
733 uv__cf_loop_state_t*
state;
737 state->loop = pCFRunLoopGetCurrent();
739 pCFRunLoopAddSource(
state->loop,
740 state->signal_source,
741 *pkCFRunLoopDefaultMode);
746 pCFRunLoopRemoveSource(
state->loop,
747 state->signal_source,
748 *pkCFRunLoopDefaultMode);
757 static void uv__cf_loop_cb(
void*
arg) {
759 uv__cf_loop_state_t*
state;
762 uv__cf_loop_signal_t*
s;
778 if (
s->handle == NULL)
779 pCFRunLoopStop(
state->loop);
781 uv__fsevents_reschedule(
s->handle,
s->type);
791 uv__cf_loop_signal_type_t
type) {
792 uv__cf_loop_signal_t* item;
793 uv__cf_loop_state_t*
state;
806 assert(
state != NULL);
807 pCFRunLoopSourceSignal(
state->signal_source);
808 pCFRunLoopWakeUp(
state->loop);
819 uv__cf_loop_state_t*
state;
821 err = uv__fsevents_loop_init(
handle->loop);
827 if (
handle->realpath == NULL)
840 if (
handle->cf_cb == NULL) {
842 goto fail_cf_cb_malloc;
852 goto fail_cf_mutex_init;
858 state->fsevent_handle_count++;
859 state->fsevent_need_reschedule = 1;
864 err = uv__cf_loop_signal(
handle->loop,
handle, kUVCFLoopSignalRegular);
866 goto fail_loop_signal;
889 uv__cf_loop_state_t*
state;
891 if (
handle->cf_cb == NULL)
898 state->fsevent_handle_count--;
899 state->fsevent_need_reschedule = 1;
904 err = uv__cf_loop_signal(
handle->loop,
handle, kUVCFLoopSignalClosing);
915 UV__FSEVENTS_PROCESS(
handle, {