Home | History | Annotate | Line # | Download | only in unix
      1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
      2  * Permission is hereby granted, free of charge, to any person obtaining a copy
      3  * of this software and associated documentation files (the "Software"), to
      4  * deal in the Software without restriction, including without limitation the
      5  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      6  * sell copies of the Software, and to permit persons to whom the Software is
      7  * furnished to do so, subject to the following conditions:
      8  *
      9  * The above copyright notice and this permission notice shall be included in
     10  * all copies or substantial portions of the Software.
     11  *
     12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     17  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     18  * IN THE SOFTWARE.
     19  */
     20 
     21 #include "uv.h"
     22 #include "internal.h"
     23 
     24 #if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
     25 
     26 /* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
     27 /* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */
     28 
     29 int uv__fsevents_init(uv_fs_event_t* handle) {
     30   return 0;
     31 }
     32 
     33 
     34 int uv__fsevents_close(uv_fs_event_t* handle) {
     35   return 0;
     36 }
     37 
     38 
     39 void uv__fsevents_loop_delete(uv_loop_t* loop) {
     40 }
     41 
     42 #else /* TARGET_OS_IPHONE */
     43 
     44 #include "darwin-stub.h"
     45 
     46 #include <dlfcn.h>
     47 #include <assert.h>
     48 #include <stdlib.h>
     49 #include <pthread.h>
     50 
     51 static const int kFSEventsModified =
     52     kFSEventStreamEventFlagItemChangeOwner |
     53     kFSEventStreamEventFlagItemFinderInfoMod |
     54     kFSEventStreamEventFlagItemInodeMetaMod |
     55     kFSEventStreamEventFlagItemModified |
     56     kFSEventStreamEventFlagItemXattrMod;
     57 
     58 static const int kFSEventsRenamed =
     59     kFSEventStreamEventFlagItemCreated |
     60     kFSEventStreamEventFlagItemRemoved |
     61     kFSEventStreamEventFlagItemRenamed;
     62 
     63 static const int kFSEventsSystem =
     64     kFSEventStreamEventFlagUserDropped |
     65     kFSEventStreamEventFlagKernelDropped |
     66     kFSEventStreamEventFlagEventIdsWrapped |
     67     kFSEventStreamEventFlagHistoryDone |
     68     kFSEventStreamEventFlagMount |
     69     kFSEventStreamEventFlagUnmount |
     70     kFSEventStreamEventFlagRootChanged;
     71 
     72 typedef struct uv__fsevents_event_s uv__fsevents_event_t;
     73 typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
     74 typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
     75 
     76 enum uv__cf_loop_signal_type_e {
     77   kUVCFLoopSignalRegular,
     78   kUVCFLoopSignalClosing
     79 };
     80 typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
     81 
     82 struct uv__cf_loop_signal_s {
     83   struct uv__queue member;
     84   uv_fs_event_t* handle;
     85   uv__cf_loop_signal_type_t type;
     86 };
     87 
     88 struct uv__fsevents_event_s {
     89   struct uv__queue member;
     90   int events;
     91   char path[1];
     92 };
     93 
     94 struct uv__cf_loop_state_s {
     95   CFRunLoopRef loop;
     96   CFRunLoopSourceRef signal_source;
     97   int fsevent_need_reschedule;
     98   FSEventStreamRef fsevent_stream;
     99   uv_sem_t fsevent_sem;
    100   uv_mutex_t fsevent_mutex;
    101   struct uv__queue fsevent_handles;
    102   unsigned int fsevent_handle_count;
    103 };
    104 
    105 /* Forward declarations */
    106 static void uv__cf_loop_cb(void* arg);
    107 static void* uv__cf_loop_runner(void* arg);
    108 static int uv__cf_loop_signal(uv_loop_t* loop,
    109                               uv_fs_event_t* handle,
    110                               uv__cf_loop_signal_type_t type);
    111 
    112 /* Lazy-loaded by uv__fsevents_global_init(). */
    113 static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
    114                                     const void**,
    115                                     CFIndex,
    116                                     const CFArrayCallBacks*);
    117 static void (*pCFRelease)(CFTypeRef);
    118 static void (*pCFRunLoopAddSource)(CFRunLoopRef,
    119                                    CFRunLoopSourceRef,
    120                                    CFStringRef);
    121 static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
    122 static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
    123                                       CFRunLoopSourceRef,
    124                                       CFStringRef);
    125 static void (*pCFRunLoopRun)(void);
    126 static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
    127                                                     CFIndex,
    128                                                     CFRunLoopSourceContext*);
    129 static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
    130 static void (*pCFRunLoopStop)(CFRunLoopRef);
    131 static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
    132 static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
    133     CFAllocatorRef,
    134     const char*);
    135 static CFStringRef (*pkCFRunLoopDefaultMode);
    136 static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
    137                                                 FSEventStreamCallback,
    138                                                 FSEventStreamContext*,
    139                                                 CFArrayRef,
    140                                                 FSEventStreamEventId,
    141                                                 CFTimeInterval,
    142                                                 FSEventStreamCreateFlags);
    143 static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
    144 static void (*pFSEventStreamRelease)(FSEventStreamRef);
    145 static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
    146                                                  CFRunLoopRef,
    147                                                  CFStringRef);
    148 static int (*pFSEventStreamStart)(FSEventStreamRef);
    149 static void (*pFSEventStreamStop)(FSEventStreamRef);
    150 
    151 #define UV__FSEVENTS_PROCESS(handle, block)                                   \
    152     do {                                                                      \
    153       struct uv__queue events;                                                \
    154       struct uv__queue* q;                                                    \
    155       uv__fsevents_event_t* event;                                            \
    156       int err;                                                                \
    157       uv_mutex_lock(&(handle)->cf_mutex);                                     \
    158       /* Split-off all events and empty original queue */                     \
    159       uv__queue_move(&(handle)->cf_events, &events);                          \
    160       /* Get error (if any) and zero original one */                          \
    161       err = (handle)->cf_error;                                               \
    162       (handle)->cf_error = 0;                                                 \
    163       uv_mutex_unlock(&(handle)->cf_mutex);                                   \
    164       /* Loop through events, deallocating each after processing */           \
    165       while (!uv__queue_empty(&events)) {                                     \
    166         q = uv__queue_head(&events);                                          \
    167         event = uv__queue_data(q, uv__fsevents_event_t, member);              \
    168         uv__queue_remove(q);                                                  \
    169         /* NOTE: Checking uv__is_active() is required here, because handle    \
    170          * callback may close handle and invoking it after it will lead to    \
    171          * incorrect behaviour */                                             \
    172         if (!uv__is_closing((handle)) && uv__is_active((handle)))             \
    173           block                                                               \
    174         /* Free allocated data */                                             \
    175         uv__free(event);                                                      \
    176       }                                                                       \
    177       if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle)))   \
    178         (handle)->cb((handle), NULL, 0, err);                                 \
    179     } while (0)
    180 
    181 
    182 /* Runs in UV loop's thread, when there're events to report to handle */
    183 static void uv__fsevents_cb(uv_async_t* cb) {
    184   uv_fs_event_t* handle;
    185 
    186   handle = cb->data;
    187 
    188   UV__FSEVENTS_PROCESS(handle, {
    189     handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
    190   });
    191 }
    192 
    193 
    194 /* Runs in CF thread, pushed event into handle's event list */
    195 static void uv__fsevents_push_event(uv_fs_event_t* handle,
    196                                     struct uv__queue* events,
    197                                     int err) {
    198   assert(events != NULL || err != 0);
    199   uv_mutex_lock(&handle->cf_mutex);
    200 
    201   /* Concatenate two queues */
    202   if (events != NULL)
    203     uv__queue_add(&handle->cf_events, events);
    204 
    205   /* Propagate error */
    206   if (err != 0)
    207     handle->cf_error = err;
    208   uv_mutex_unlock(&handle->cf_mutex);
    209 
    210   uv_async_send(handle->cf_cb);
    211 }
    212 
    213 
    214 /* Runs in CF thread, when there're events in FSEventStream */
    215 static void uv__fsevents_event_cb(const FSEventStreamRef streamRef,
    216                                   void* info,
    217                                   size_t numEvents,
    218                                   void* eventPaths,
    219                                   const FSEventStreamEventFlags eventFlags[],
    220                                   const FSEventStreamEventId eventIds[]) {
    221   size_t i;
    222   int len;
    223   char** paths;
    224   char* path;
    225   char* pos;
    226   uv_fs_event_t* handle;
    227   struct uv__queue* q;
    228   uv_loop_t* loop;
    229   uv__cf_loop_state_t* state;
    230   uv__fsevents_event_t* event;
    231   FSEventStreamEventFlags flags;
    232   struct uv__queue head;
    233 
    234   loop = info;
    235   state = loop->cf_state;
    236   assert(state != NULL);
    237   paths = eventPaths;
    238 
    239   /* For each handle */
    240   uv_mutex_lock(&state->fsevent_mutex);
    241   uv__queue_foreach(q, &state->fsevent_handles) {
    242     handle = uv__queue_data(q, uv_fs_event_t, cf_member);
    243     uv__queue_init(&head);
    244 
    245     /* Process and filter out events */
    246     for (i = 0; i < numEvents; i++) {
    247       flags = eventFlags[i];
    248 
    249       /* Ignore system events */
    250       if (flags & kFSEventsSystem)
    251         continue;
    252 
    253       path = paths[i];
    254       len = strlen(path);
    255 
    256       if (handle->realpath_len == 0)
    257         continue; /* This should be unreachable */
    258 
    259       /* Filter out paths that are outside handle's request */
    260       if (len < handle->realpath_len)
    261         continue;
    262 
    263       /* Make sure that realpath actually named a directory,
    264        * (unless watching root, which alone keeps a trailing slash on the realpath)
    265        * or that we matched the whole string */
    266       if (handle->realpath_len != len &&
    267           handle->realpath_len > 1 &&
    268           path[handle->realpath_len] != '/')
    269         continue;
    270 
    271       if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
    272         continue;
    273 
    274       if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
    275         /* Remove common prefix, unless the watched folder is "/" */
    276         path += handle->realpath_len;
    277         len -= handle->realpath_len;
    278 
    279         if (len == 0) {
    280           /* Since we're using fsevents to watch the file itself,
    281            * realpath == path, and we now need to get the basename of the file back
    282            * (for commonality with other codepaths and platforms). */
    283           while (len < handle->realpath_len && path[-1] != '/') {
    284             path--;
    285             len++;
    286           }
    287           /* Created and Removed seem to be always set, but don't make sense */
    288           flags &= ~kFSEventsRenamed;
    289         } else {
    290           /* Skip forward slash */
    291           path++;
    292           len--;
    293         }
    294       }
    295 
    296       /* Do not emit events from subdirectories (without option set) */
    297       if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
    298         pos = strchr(path + 1, '/');
    299         if (pos != NULL)
    300           continue;
    301       }
    302 
    303       event = uv__malloc(sizeof(*event) + len);
    304       if (event == NULL)
    305         break;
    306 
    307       memset(event, 0, sizeof(*event));
    308       memcpy(event->path, path, len + 1);
    309       event->events = UV_RENAME;
    310 
    311       if (0 == (flags & kFSEventsRenamed)) {
    312         if (0 != (flags & kFSEventsModified) ||
    313             0 == (flags & kFSEventStreamEventFlagItemIsDir))
    314           event->events = UV_CHANGE;
    315       }
    316 
    317       uv__queue_insert_tail(&head, &event->member);
    318     }
    319 
    320     if (!uv__queue_empty(&head))
    321       uv__fsevents_push_event(handle, &head, 0);
    322   }
    323   uv_mutex_unlock(&state->fsevent_mutex);
    324 }
    325 
    326 
    327 /* Runs in CF thread */
    328 static int uv__fsevents_create_stream(uv__cf_loop_state_t* state,
    329                                       uv_loop_t* loop,
    330                                       CFArrayRef paths) {
    331   FSEventStreamContext ctx;
    332   FSEventStreamRef ref;
    333   CFAbsoluteTime latency;
    334   FSEventStreamCreateFlags flags;
    335 
    336   /* Initialize context */
    337   memset(&ctx, 0, sizeof(ctx));
    338   ctx.info = loop;
    339 
    340   latency = 0.05;
    341 
    342   /* Explanation of selected flags:
    343    * 1. NoDefer - without this flag, events that are happening continuously
    344    *    (i.e. each event is happening after time interval less than `latency`,
    345    *    counted from previous event), will be deferred and passed to callback
    346    *    once they'll either fill whole OS buffer, or when this continuous stream
    347    *    will stop (i.e. there'll be delay between events, bigger than
    348    *    `latency`).
    349    *    Specifying this flag will invoke callback after `latency` time passed
    350    *    since event.
    351    * 2. FileEvents - fire callback for file changes too (by default it is firing
    352    *    it only for directory changes).
    353    */
    354   flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
    355 
    356   /*
    357    * NOTE: It might sound like a good idea to remember last seen StreamEventId,
    358    * but in reality one dir might have last StreamEventId less than, the other,
    359    * that is being watched now. Which will cause FSEventStream API to report
    360    * changes to files from the past.
    361    */
    362   ref = pFSEventStreamCreate(NULL,
    363                              &uv__fsevents_event_cb,
    364                              &ctx,
    365                              paths,
    366                              kFSEventStreamEventIdSinceNow,
    367                              latency,
    368                              flags);
    369   assert(ref != NULL);
    370 
    371   pFSEventStreamScheduleWithRunLoop(ref, state->loop, *pkCFRunLoopDefaultMode);
    372   if (!pFSEventStreamStart(ref)) {
    373     pFSEventStreamInvalidate(ref);
    374     pFSEventStreamRelease(ref);
    375     return UV_EMFILE;
    376   }
    377 
    378   state->fsevent_stream = ref;
    379   return 0;
    380 }
    381 
    382 
    383 /* Runs in CF thread */
    384 static void uv__fsevents_destroy_stream(uv__cf_loop_state_t* state) {
    385   if (state->fsevent_stream == NULL)
    386     return;
    387 
    388   /* Stop emitting events */
    389   pFSEventStreamStop(state->fsevent_stream);
    390 
    391   /* Release stream */
    392   pFSEventStreamInvalidate(state->fsevent_stream);
    393   pFSEventStreamRelease(state->fsevent_stream);
    394   state->fsevent_stream = NULL;
    395 }
    396 
    397 
    398 /* Runs in CF thread, when there're new fsevent handles to add to stream */
    399 static void uv__fsevents_reschedule(uv__cf_loop_state_t* state,
    400                                     uv_loop_t* loop,
    401                                     uv__cf_loop_signal_type_t type) {
    402   struct uv__queue* q;
    403   uv_fs_event_t* curr;
    404   CFArrayRef cf_paths;
    405   CFStringRef* paths;
    406   unsigned int i;
    407   int err;
    408   unsigned int path_count;
    409 
    410   paths = NULL;
    411   cf_paths = NULL;
    412   err = 0;
    413   /* NOTE: `i` is used in deallocation loop below */
    414   i = 0;
    415 
    416   /* Optimization to prevent O(n^2) time spent when starting to watch
    417    * many files simultaneously
    418    */
    419   uv_mutex_lock(&state->fsevent_mutex);
    420   if (state->fsevent_need_reschedule == 0) {
    421     uv_mutex_unlock(&state->fsevent_mutex);
    422     goto final;
    423   }
    424   state->fsevent_need_reschedule = 0;
    425   uv_mutex_unlock(&state->fsevent_mutex);
    426 
    427   /* Destroy previous FSEventStream */
    428   uv__fsevents_destroy_stream(state);
    429 
    430   /* Any failure below will be a memory failure */
    431   err = UV_ENOMEM;
    432 
    433   /* Create list of all watched paths */
    434   uv_mutex_lock(&state->fsevent_mutex);
    435   path_count = state->fsevent_handle_count;
    436   if (path_count != 0) {
    437     paths = uv__malloc(sizeof(*paths) * path_count);
    438     if (paths == NULL) {
    439       uv_mutex_unlock(&state->fsevent_mutex);
    440       goto final;
    441     }
    442 
    443     q = &state->fsevent_handles;
    444     for (; i < path_count; i++) {
    445       q = uv__queue_next(q);
    446       assert(q != &state->fsevent_handles);
    447       curr = uv__queue_data(q, uv_fs_event_t, cf_member);
    448 
    449       assert(curr->realpath != NULL);
    450       paths[i] =
    451           pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
    452       if (paths[i] == NULL) {
    453         uv_mutex_unlock(&state->fsevent_mutex);
    454         goto final;
    455       }
    456     }
    457   }
    458   uv_mutex_unlock(&state->fsevent_mutex);
    459   err = 0;
    460 
    461   if (path_count != 0) {
    462     /* Create new FSEventStream */
    463     cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
    464     if (cf_paths == NULL) {
    465       err = UV_ENOMEM;
    466       goto final;
    467     }
    468     err = uv__fsevents_create_stream(state, loop, cf_paths);
    469   }
    470 
    471 final:
    472   /* Deallocate all paths in case of failure */
    473   if (err != 0) {
    474     if (cf_paths == NULL) {
    475       while (i != 0)
    476         pCFRelease(paths[--i]);
    477       uv__free(paths);
    478     } else {
    479       /* CFArray takes ownership of both strings and original C-array */
    480       pCFRelease(cf_paths);
    481     }
    482 
    483     /* Broadcast error to all handles */
    484     uv_mutex_lock(&state->fsevent_mutex);
    485     uv__queue_foreach(q, &state->fsevent_handles) {
    486       curr = uv__queue_data(q, uv_fs_event_t, cf_member);
    487       uv__fsevents_push_event(curr, NULL, err);
    488     }
    489     uv_mutex_unlock(&state->fsevent_mutex);
    490   }
    491 
    492   /*
    493    * Main thread will block until the removal of handle from the list,
    494    * we must tell it when we're ready.
    495    *
    496    * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
    497    */
    498   if (type == kUVCFLoopSignalClosing)
    499     uv_sem_post(&state->fsevent_sem);
    500 }
    501 
    502 
    503 static int uv__fsevents_global_init(void) {
    504   static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
    505   static void* core_foundation_handle;
    506   static void* core_services_handle;
    507   int err;
    508 
    509   err = 0;
    510   pthread_mutex_lock(&global_init_mutex);
    511   if (core_foundation_handle != NULL)
    512     goto out;
    513 
    514   /* The libraries are never unloaded because we currently don't have a good
    515    * mechanism for keeping a reference count. It's unlikely to be an issue
    516    * but if it ever becomes one, we can turn the dynamic library handles into
    517    * per-event loop properties and have the dynamic linker keep track for us.
    518    */
    519   err = UV_ENOSYS;
    520   core_foundation_handle = dlopen("/System/Library/Frameworks/"
    521                                   "CoreFoundation.framework/"
    522                                   "Versions/A/CoreFoundation",
    523                                   RTLD_LAZY | RTLD_LOCAL);
    524   if (core_foundation_handle == NULL)
    525     goto out;
    526 
    527   core_services_handle = dlopen("/System/Library/Frameworks/"
    528                                 "CoreServices.framework/"
    529                                 "Versions/A/CoreServices",
    530                                 RTLD_LAZY | RTLD_LOCAL);
    531   if (core_services_handle == NULL)
    532     goto out;
    533 
    534   err = UV_ENOENT;
    535 #define V(handle, symbol)                                                     \
    536   do {                                                                        \
    537     *(void **)(&p ## symbol) = dlsym((handle), #symbol);                      \
    538     if (p ## symbol == NULL)                                                  \
    539       goto out;                                                               \
    540   }                                                                           \
    541   while (0)
    542   V(core_foundation_handle, CFArrayCreate);
    543   V(core_foundation_handle, CFRelease);
    544   V(core_foundation_handle, CFRunLoopAddSource);
    545   V(core_foundation_handle, CFRunLoopGetCurrent);
    546   V(core_foundation_handle, CFRunLoopRemoveSource);
    547   V(core_foundation_handle, CFRunLoopRun);
    548   V(core_foundation_handle, CFRunLoopSourceCreate);
    549   V(core_foundation_handle, CFRunLoopSourceSignal);
    550   V(core_foundation_handle, CFRunLoopStop);
    551   V(core_foundation_handle, CFRunLoopWakeUp);
    552   V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
    553   V(core_foundation_handle, kCFRunLoopDefaultMode);
    554   V(core_services_handle, FSEventStreamCreate);
    555   V(core_services_handle, FSEventStreamInvalidate);
    556   V(core_services_handle, FSEventStreamRelease);
    557   V(core_services_handle, FSEventStreamScheduleWithRunLoop);
    558   V(core_services_handle, FSEventStreamStart);
    559   V(core_services_handle, FSEventStreamStop);
    560 #undef V
    561   err = 0;
    562 
    563 out:
    564   if (err && core_services_handle != NULL) {
    565     dlclose(core_services_handle);
    566     core_services_handle = NULL;
    567   }
    568 
    569   if (err && core_foundation_handle != NULL) {
    570     dlclose(core_foundation_handle);
    571     core_foundation_handle = NULL;
    572   }
    573 
    574   pthread_mutex_unlock(&global_init_mutex);
    575   return err;
    576 }
    577 
    578 
    579 /* Runs in UV loop */
    580 static int uv__fsevents_loop_init(uv_loop_t* loop) {
    581   CFRunLoopSourceContext ctx;
    582   uv__cf_loop_state_t* state;
    583   pthread_attr_t attr;
    584   int err;
    585 
    586   if (loop->cf_state != NULL)
    587     return 0;
    588 
    589   err = uv__fsevents_global_init();
    590   if (err)
    591     return err;
    592 
    593   state = uv__calloc(1, sizeof(*state));
    594   if (state == NULL)
    595     return UV_ENOMEM;
    596 
    597   err = uv_mutex_init(&loop->cf_mutex);
    598   if (err)
    599     goto fail_mutex_init;
    600 
    601   err = uv_sem_init(&loop->cf_sem, 0);
    602   if (err)
    603     goto fail_sem_init;
    604 
    605   uv__queue_init(&loop->cf_signals);
    606 
    607   err = uv_sem_init(&state->fsevent_sem, 0);
    608   if (err)
    609     goto fail_fsevent_sem_init;
    610 
    611   err = uv_mutex_init(&state->fsevent_mutex);
    612   if (err)
    613     goto fail_fsevent_mutex_init;
    614 
    615   uv__queue_init(&state->fsevent_handles);
    616   state->fsevent_need_reschedule = 0;
    617   state->fsevent_handle_count = 0;
    618 
    619   memset(&ctx, 0, sizeof(ctx));
    620   ctx.info = loop;
    621   ctx.perform = uv__cf_loop_cb;
    622   state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
    623   if (state->signal_source == NULL) {
    624     err = UV_ENOMEM;
    625     goto fail_signal_source_create;
    626   }
    627 
    628   if (pthread_attr_init(&attr))
    629     abort();
    630 
    631   if (pthread_attr_setstacksize(&attr, uv__thread_stack_size()))
    632     abort();
    633 
    634   loop->cf_state = state;
    635 
    636   /* uv_thread_t is an alias for pthread_t. */
    637   err = UV__ERR(pthread_create(&loop->cf_thread, &attr, uv__cf_loop_runner, loop));
    638 
    639   if (pthread_attr_destroy(&attr))
    640     abort();
    641 
    642   if (err)
    643     goto fail_thread_create;
    644 
    645   /* Synchronize threads */
    646   uv_sem_wait(&loop->cf_sem);
    647   return 0;
    648 
    649 fail_thread_create:
    650   loop->cf_state = NULL;
    651 
    652 fail_signal_source_create:
    653   uv_mutex_destroy(&state->fsevent_mutex);
    654 
    655 fail_fsevent_mutex_init:
    656   uv_sem_destroy(&state->fsevent_sem);
    657 
    658 fail_fsevent_sem_init:
    659   uv_sem_destroy(&loop->cf_sem);
    660 
    661 fail_sem_init:
    662   uv_mutex_destroy(&loop->cf_mutex);
    663 
    664 fail_mutex_init:
    665   uv__free(state);
    666   return err;
    667 }
    668 
    669 
    670 /* Runs in UV loop */
    671 void uv__fsevents_loop_delete(uv_loop_t* loop) {
    672   uv__cf_loop_signal_t* s;
    673   uv__cf_loop_state_t* state;
    674   struct uv__queue* q;
    675 
    676   if (loop->cf_state == NULL)
    677     return;
    678 
    679   if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
    680     abort();
    681 
    682   uv_thread_join(&loop->cf_thread);
    683   uv_sem_destroy(&loop->cf_sem);
    684   uv_mutex_destroy(&loop->cf_mutex);
    685 
    686   /* Free any remaining data */
    687   while (!uv__queue_empty(&loop->cf_signals)) {
    688     q = uv__queue_head(&loop->cf_signals);
    689     s = uv__queue_data(q, uv__cf_loop_signal_t, member);
    690     uv__queue_remove(q);
    691     uv__free(s);
    692   }
    693 
    694   /* Destroy state */
    695   state = loop->cf_state;
    696   uv_sem_destroy(&state->fsevent_sem);
    697   uv_mutex_destroy(&state->fsevent_mutex);
    698   pCFRelease(state->signal_source);
    699   uv__free(state);
    700   loop->cf_state = NULL;
    701 }
    702 
    703 
    704 /* Runs in CF thread. This is the CF loop's body */
    705 static void* uv__cf_loop_runner(void* arg) {
    706   uv_loop_t* loop;
    707   uv__cf_loop_state_t* state;
    708 
    709   loop = arg;
    710   state = loop->cf_state;
    711   state->loop = pCFRunLoopGetCurrent();
    712 
    713   pCFRunLoopAddSource(state->loop,
    714                       state->signal_source,
    715                       *pkCFRunLoopDefaultMode);
    716 
    717   uv_sem_post(&loop->cf_sem);
    718 
    719   pCFRunLoopRun();
    720   pCFRunLoopRemoveSource(state->loop,
    721                          state->signal_source,
    722                          *pkCFRunLoopDefaultMode);
    723 
    724   state->loop = NULL;
    725 
    726   return NULL;
    727 }
    728 
    729 
    730 /* Runs in CF thread, executed after `uv__cf_loop_signal()` */
    731 static void uv__cf_loop_cb(void* arg) {
    732   uv_loop_t* loop;
    733   uv__cf_loop_state_t* state;
    734   struct uv__queue* item;
    735   struct uv__queue split_head;
    736   uv__cf_loop_signal_t* s;
    737 
    738   loop = arg;
    739   state = loop->cf_state;
    740 
    741   uv_mutex_lock(&loop->cf_mutex);
    742   uv__queue_move(&loop->cf_signals, &split_head);
    743   uv_mutex_unlock(&loop->cf_mutex);
    744 
    745   while (!uv__queue_empty(&split_head)) {
    746     item = uv__queue_head(&split_head);
    747     uv__queue_remove(item);
    748 
    749     s = uv__queue_data(item, uv__cf_loop_signal_t, member);
    750 
    751     /* This was a termination signal */
    752     if (s->handle == NULL)
    753       pCFRunLoopStop(state->loop);
    754     else
    755       uv__fsevents_reschedule(state, loop, s->type);
    756 
    757     uv__free(s);
    758   }
    759 }
    760 
    761 
    762 /* Runs in UV loop to notify CF thread */
    763 int uv__cf_loop_signal(uv_loop_t* loop,
    764                        uv_fs_event_t* handle,
    765                        uv__cf_loop_signal_type_t type) {
    766   uv__cf_loop_signal_t* item;
    767   uv__cf_loop_state_t* state;
    768 
    769   item = uv__malloc(sizeof(*item));
    770   if (item == NULL)
    771     return UV_ENOMEM;
    772 
    773   item->handle = handle;
    774   item->type = type;
    775 
    776   uv_mutex_lock(&loop->cf_mutex);
    777   uv__queue_insert_tail(&loop->cf_signals, &item->member);
    778 
    779   state = loop->cf_state;
    780   assert(state != NULL);
    781   pCFRunLoopSourceSignal(state->signal_source);
    782   pCFRunLoopWakeUp(state->loop);
    783 
    784   uv_mutex_unlock(&loop->cf_mutex);
    785 
    786   return 0;
    787 }
    788 
    789 
    790 /* Runs in UV loop to initialize handle */
    791 int uv__fsevents_init(uv_fs_event_t* handle) {
    792   char* buf;
    793   int err;
    794   uv__cf_loop_state_t* state;
    795 
    796   err = uv__fsevents_loop_init(handle->loop);
    797   if (err)
    798     return err;
    799 
    800   /* Get absolute path to file */
    801   buf = realpath(handle->path, NULL);
    802   if (buf == NULL)
    803     return UV__ERR(errno);
    804   handle->realpath = uv__strdup(buf);
    805   free(buf); /* _Not_ uv__free. */
    806   if (handle->realpath == NULL)
    807     return UV_ENOMEM;
    808   handle->realpath_len = strlen(handle->realpath);
    809 
    810   /* Initialize event queue */
    811   uv__queue_init(&handle->cf_events);
    812   handle->cf_error = 0;
    813 
    814   /*
    815    * Events will occur in other thread.
    816    * Initialize callback for getting them back into event loop's thread
    817    */
    818   handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
    819   if (handle->cf_cb == NULL) {
    820     err = UV_ENOMEM;
    821     goto fail_cf_cb_malloc;
    822   }
    823 
    824   handle->cf_cb->data = handle;
    825   uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
    826   handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
    827   uv_unref((uv_handle_t*) handle->cf_cb);
    828 
    829   err = uv_mutex_init(&handle->cf_mutex);
    830   if (err)
    831     goto fail_cf_mutex_init;
    832 
    833   /* Insert handle into the list */
    834   state = handle->loop->cf_state;
    835   uv_mutex_lock(&state->fsevent_mutex);
    836   uv__queue_insert_tail(&state->fsevent_handles, &handle->cf_member);
    837   state->fsevent_handle_count++;
    838   state->fsevent_need_reschedule = 1;
    839   uv_mutex_unlock(&state->fsevent_mutex);
    840 
    841   /* Reschedule FSEventStream */
    842   assert(handle != NULL);
    843   err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
    844   if (err)
    845     goto fail_loop_signal;
    846 
    847   return 0;
    848 
    849 fail_loop_signal:
    850   uv_mutex_destroy(&handle->cf_mutex);
    851 
    852 fail_cf_mutex_init:
    853   uv__free(handle->cf_cb);
    854   handle->cf_cb = NULL;
    855 
    856 fail_cf_cb_malloc:
    857   uv__free(handle->realpath);
    858   handle->realpath = NULL;
    859   handle->realpath_len = 0;
    860 
    861   return err;
    862 }
    863 
    864 
    865 /* Runs in UV loop to de-initialize handle */
    866 int uv__fsevents_close(uv_fs_event_t* handle) {
    867   int err;
    868   uv__cf_loop_state_t* state;
    869 
    870   if (handle->cf_cb == NULL)
    871     return UV_EINVAL;
    872 
    873   /* Remove handle from  the list */
    874   state = handle->loop->cf_state;
    875   uv_mutex_lock(&state->fsevent_mutex);
    876   uv__queue_remove(&handle->cf_member);
    877   state->fsevent_handle_count--;
    878   state->fsevent_need_reschedule = 1;
    879   uv_mutex_unlock(&state->fsevent_mutex);
    880 
    881   /* Reschedule FSEventStream */
    882   assert(handle != NULL);
    883   err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
    884   if (err)
    885     return UV__ERR(err);
    886 
    887   /* Wait for deinitialization */
    888   uv_sem_wait(&state->fsevent_sem);
    889 
    890   uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
    891   handle->cf_cb = NULL;
    892 
    893   /* Free data in queue */
    894   UV__FSEVENTS_PROCESS(handle, {
    895     /* NOP */
    896   });
    897 
    898   uv_mutex_destroy(&handle->cf_mutex);
    899   uv__free(handle->realpath);
    900   handle->realpath = NULL;
    901   handle->realpath_len = 0;
    902 
    903   return 0;
    904 }
    905 
    906 #endif /* TARGET_OS_IPHONE */
    907