11cb0ef41Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 21cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 31cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to 41cb0ef41Sopenharmony_ci * deal in the Software without restriction, including without limitation the 51cb0ef41Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 61cb0ef41Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 71cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions: 81cb0ef41Sopenharmony_ci * 91cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 101cb0ef41Sopenharmony_ci * all copies or substantial portions of the Software. 111cb0ef41Sopenharmony_ci * 121cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 131cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 141cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 151cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 161cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 171cb0ef41Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 181cb0ef41Sopenharmony_ci * IN THE SOFTWARE. 191cb0ef41Sopenharmony_ci */ 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci#include "uv.h" 221cb0ef41Sopenharmony_ci#include "internal.h" 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */ 271cb0ef41Sopenharmony_ci/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */ 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ciint uv__fsevents_init(uv_fs_event_t* handle) { 301cb0ef41Sopenharmony_ci return 0; 311cb0ef41Sopenharmony_ci} 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ciint uv__fsevents_close(uv_fs_event_t* handle) { 351cb0ef41Sopenharmony_ci return 0; 361cb0ef41Sopenharmony_ci} 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_civoid uv__fsevents_loop_delete(uv_loop_t* loop) { 401cb0ef41Sopenharmony_ci} 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci#else /* TARGET_OS_IPHONE */ 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci#include "darwin-stub.h" 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci#include <dlfcn.h> 471cb0ef41Sopenharmony_ci#include <assert.h> 481cb0ef41Sopenharmony_ci#include <stdlib.h> 491cb0ef41Sopenharmony_ci#include <pthread.h> 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_cistatic const int kFSEventsModified = 521cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemChangeOwner | 531cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemFinderInfoMod | 541cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemInodeMetaMod | 551cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemModified | 561cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemXattrMod; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_cistatic const int kFSEventsRenamed = 591cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemCreated | 601cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemRemoved | 611cb0ef41Sopenharmony_ci kFSEventStreamEventFlagItemRenamed; 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_cistatic const int kFSEventsSystem = 641cb0ef41Sopenharmony_ci kFSEventStreamEventFlagUserDropped | 651cb0ef41Sopenharmony_ci kFSEventStreamEventFlagKernelDropped | 661cb0ef41Sopenharmony_ci kFSEventStreamEventFlagEventIdsWrapped | 671cb0ef41Sopenharmony_ci kFSEventStreamEventFlagHistoryDone | 681cb0ef41Sopenharmony_ci kFSEventStreamEventFlagMount | 691cb0ef41Sopenharmony_ci kFSEventStreamEventFlagUnmount | 701cb0ef41Sopenharmony_ci kFSEventStreamEventFlagRootChanged; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_citypedef struct uv__fsevents_event_s uv__fsevents_event_t; 731cb0ef41Sopenharmony_citypedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; 741cb0ef41Sopenharmony_citypedef struct uv__cf_loop_state_s uv__cf_loop_state_t; 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_cienum uv__cf_loop_signal_type_e { 771cb0ef41Sopenharmony_ci kUVCFLoopSignalRegular, 781cb0ef41Sopenharmony_ci kUVCFLoopSignalClosing 791cb0ef41Sopenharmony_ci}; 801cb0ef41Sopenharmony_citypedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_cistruct uv__cf_loop_signal_s { 831cb0ef41Sopenharmony_ci QUEUE member; 841cb0ef41Sopenharmony_ci uv_fs_event_t* handle; 851cb0ef41Sopenharmony_ci uv__cf_loop_signal_type_t type; 861cb0ef41Sopenharmony_ci}; 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_cistruct uv__fsevents_event_s { 891cb0ef41Sopenharmony_ci QUEUE member; 901cb0ef41Sopenharmony_ci int events; 911cb0ef41Sopenharmony_ci char path[1]; 921cb0ef41Sopenharmony_ci}; 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_cistruct uv__cf_loop_state_s { 951cb0ef41Sopenharmony_ci CFRunLoopRef loop; 961cb0ef41Sopenharmony_ci CFRunLoopSourceRef signal_source; 971cb0ef41Sopenharmony_ci int fsevent_need_reschedule; 981cb0ef41Sopenharmony_ci FSEventStreamRef fsevent_stream; 991cb0ef41Sopenharmony_ci uv_sem_t fsevent_sem; 1001cb0ef41Sopenharmony_ci uv_mutex_t fsevent_mutex; 1011cb0ef41Sopenharmony_ci void* fsevent_handles[2]; 1021cb0ef41Sopenharmony_ci unsigned int fsevent_handle_count; 1031cb0ef41Sopenharmony_ci}; 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci/* Forward declarations */ 1061cb0ef41Sopenharmony_cistatic void uv__cf_loop_cb(void* arg); 1071cb0ef41Sopenharmony_cistatic void* uv__cf_loop_runner(void* arg); 1081cb0ef41Sopenharmony_cistatic int uv__cf_loop_signal(uv_loop_t* loop, 1091cb0ef41Sopenharmony_ci uv_fs_event_t* handle, 1101cb0ef41Sopenharmony_ci uv__cf_loop_signal_type_t type); 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci/* Lazy-loaded by uv__fsevents_global_init(). */ 1131cb0ef41Sopenharmony_cistatic CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, 1141cb0ef41Sopenharmony_ci const void**, 1151cb0ef41Sopenharmony_ci CFIndex, 1161cb0ef41Sopenharmony_ci const CFArrayCallBacks*); 1171cb0ef41Sopenharmony_cistatic void (*pCFRelease)(CFTypeRef); 1181cb0ef41Sopenharmony_cistatic void (*pCFRunLoopAddSource)(CFRunLoopRef, 1191cb0ef41Sopenharmony_ci CFRunLoopSourceRef, 1201cb0ef41Sopenharmony_ci CFStringRef); 1211cb0ef41Sopenharmony_cistatic CFRunLoopRef (*pCFRunLoopGetCurrent)(void); 1221cb0ef41Sopenharmony_cistatic void (*pCFRunLoopRemoveSource)(CFRunLoopRef, 1231cb0ef41Sopenharmony_ci CFRunLoopSourceRef, 1241cb0ef41Sopenharmony_ci CFStringRef); 1251cb0ef41Sopenharmony_cistatic void (*pCFRunLoopRun)(void); 1261cb0ef41Sopenharmony_cistatic CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef, 1271cb0ef41Sopenharmony_ci CFIndex, 1281cb0ef41Sopenharmony_ci CFRunLoopSourceContext*); 1291cb0ef41Sopenharmony_cistatic void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef); 1301cb0ef41Sopenharmony_cistatic void (*pCFRunLoopStop)(CFRunLoopRef); 1311cb0ef41Sopenharmony_cistatic void (*pCFRunLoopWakeUp)(CFRunLoopRef); 1321cb0ef41Sopenharmony_cistatic CFStringRef (*pCFStringCreateWithFileSystemRepresentation)( 1331cb0ef41Sopenharmony_ci CFAllocatorRef, 1341cb0ef41Sopenharmony_ci const char*); 1351cb0ef41Sopenharmony_cistatic CFStringEncoding (*pCFStringGetSystemEncoding)(void); 1361cb0ef41Sopenharmony_cistatic CFStringRef (*pkCFRunLoopDefaultMode); 1371cb0ef41Sopenharmony_cistatic FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef, 1381cb0ef41Sopenharmony_ci FSEventStreamCallback, 1391cb0ef41Sopenharmony_ci FSEventStreamContext*, 1401cb0ef41Sopenharmony_ci CFArrayRef, 1411cb0ef41Sopenharmony_ci FSEventStreamEventId, 1421cb0ef41Sopenharmony_ci CFTimeInterval, 1431cb0ef41Sopenharmony_ci FSEventStreamCreateFlags); 1441cb0ef41Sopenharmony_cistatic void (*pFSEventStreamFlushSync)(FSEventStreamRef); 1451cb0ef41Sopenharmony_cistatic void (*pFSEventStreamInvalidate)(FSEventStreamRef); 1461cb0ef41Sopenharmony_cistatic void (*pFSEventStreamRelease)(FSEventStreamRef); 1471cb0ef41Sopenharmony_cistatic void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef, 1481cb0ef41Sopenharmony_ci CFRunLoopRef, 1491cb0ef41Sopenharmony_ci CFStringRef); 1501cb0ef41Sopenharmony_cistatic int (*pFSEventStreamStart)(FSEventStreamRef); 1511cb0ef41Sopenharmony_cistatic void (*pFSEventStreamStop)(FSEventStreamRef); 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci#define UV__FSEVENTS_PROCESS(handle, block) \ 1541cb0ef41Sopenharmony_ci do { \ 1551cb0ef41Sopenharmony_ci QUEUE events; \ 1561cb0ef41Sopenharmony_ci QUEUE* q; \ 1571cb0ef41Sopenharmony_ci uv__fsevents_event_t* event; \ 1581cb0ef41Sopenharmony_ci int err; \ 1591cb0ef41Sopenharmony_ci uv_mutex_lock(&(handle)->cf_mutex); \ 1601cb0ef41Sopenharmony_ci /* Split-off all events and empty original queue */ \ 1611cb0ef41Sopenharmony_ci QUEUE_MOVE(&(handle)->cf_events, &events); \ 1621cb0ef41Sopenharmony_ci /* Get error (if any) and zero original one */ \ 1631cb0ef41Sopenharmony_ci err = (handle)->cf_error; \ 1641cb0ef41Sopenharmony_ci (handle)->cf_error = 0; \ 1651cb0ef41Sopenharmony_ci uv_mutex_unlock(&(handle)->cf_mutex); \ 1661cb0ef41Sopenharmony_ci /* Loop through events, deallocating each after processing */ \ 1671cb0ef41Sopenharmony_ci while (!QUEUE_EMPTY(&events)) { \ 1681cb0ef41Sopenharmony_ci q = QUEUE_HEAD(&events); \ 1691cb0ef41Sopenharmony_ci event = QUEUE_DATA(q, uv__fsevents_event_t, member); \ 1701cb0ef41Sopenharmony_ci QUEUE_REMOVE(q); \ 1711cb0ef41Sopenharmony_ci /* NOTE: Checking uv__is_active() is required here, because handle \ 1721cb0ef41Sopenharmony_ci * callback may close handle and invoking it after it will lead to \ 1731cb0ef41Sopenharmony_ci * incorrect behaviour */ \ 1741cb0ef41Sopenharmony_ci if (!uv__is_closing((handle)) && uv__is_active((handle))) \ 1751cb0ef41Sopenharmony_ci block \ 1761cb0ef41Sopenharmony_ci /* Free allocated data */ \ 1771cb0ef41Sopenharmony_ci uv__free(event); \ 1781cb0ef41Sopenharmony_ci } \ 1791cb0ef41Sopenharmony_ci if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \ 1801cb0ef41Sopenharmony_ci (handle)->cb((handle), NULL, 0, err); \ 1811cb0ef41Sopenharmony_ci } while (0) 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci/* Runs in UV loop's thread, when there're events to report to handle */ 1851cb0ef41Sopenharmony_cistatic void uv__fsevents_cb(uv_async_t* cb) { 1861cb0ef41Sopenharmony_ci uv_fs_event_t* handle; 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci handle = cb->data; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci UV__FSEVENTS_PROCESS(handle, { 1911cb0ef41Sopenharmony_ci handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0); 1921cb0ef41Sopenharmony_ci }); 1931cb0ef41Sopenharmony_ci} 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci/* Runs in CF thread, pushed event into handle's event list */ 1971cb0ef41Sopenharmony_cistatic void uv__fsevents_push_event(uv_fs_event_t* handle, 1981cb0ef41Sopenharmony_ci QUEUE* events, 1991cb0ef41Sopenharmony_ci int err) { 2001cb0ef41Sopenharmony_ci assert(events != NULL || err != 0); 2011cb0ef41Sopenharmony_ci uv_mutex_lock(&handle->cf_mutex); 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci /* Concatenate two queues */ 2041cb0ef41Sopenharmony_ci if (events != NULL) 2051cb0ef41Sopenharmony_ci QUEUE_ADD(&handle->cf_events, events); 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci /* Propagate error */ 2081cb0ef41Sopenharmony_ci if (err != 0) 2091cb0ef41Sopenharmony_ci handle->cf_error = err; 2101cb0ef41Sopenharmony_ci uv_mutex_unlock(&handle->cf_mutex); 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci uv_async_send(handle->cf_cb); 2131cb0ef41Sopenharmony_ci} 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ci/* Runs in CF thread, when there're events in FSEventStream */ 2171cb0ef41Sopenharmony_cistatic void uv__fsevents_event_cb(const FSEventStreamRef streamRef, 2181cb0ef41Sopenharmony_ci void* info, 2191cb0ef41Sopenharmony_ci size_t numEvents, 2201cb0ef41Sopenharmony_ci void* eventPaths, 2211cb0ef41Sopenharmony_ci const FSEventStreamEventFlags eventFlags[], 2221cb0ef41Sopenharmony_ci const FSEventStreamEventId eventIds[]) { 2231cb0ef41Sopenharmony_ci size_t i; 2241cb0ef41Sopenharmony_ci int len; 2251cb0ef41Sopenharmony_ci char** paths; 2261cb0ef41Sopenharmony_ci char* path; 2271cb0ef41Sopenharmony_ci char* pos; 2281cb0ef41Sopenharmony_ci uv_fs_event_t* handle; 2291cb0ef41Sopenharmony_ci QUEUE* q; 2301cb0ef41Sopenharmony_ci uv_loop_t* loop; 2311cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 2321cb0ef41Sopenharmony_ci uv__fsevents_event_t* event; 2331cb0ef41Sopenharmony_ci FSEventStreamEventFlags flags; 2341cb0ef41Sopenharmony_ci QUEUE head; 2351cb0ef41Sopenharmony_ci 2361cb0ef41Sopenharmony_ci loop = info; 2371cb0ef41Sopenharmony_ci state = loop->cf_state; 2381cb0ef41Sopenharmony_ci assert(state != NULL); 2391cb0ef41Sopenharmony_ci paths = eventPaths; 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci /* For each handle */ 2421cb0ef41Sopenharmony_ci uv_mutex_lock(&state->fsevent_mutex); 2431cb0ef41Sopenharmony_ci QUEUE_FOREACH(q, &state->fsevent_handles) { 2441cb0ef41Sopenharmony_ci handle = QUEUE_DATA(q, uv_fs_event_t, cf_member); 2451cb0ef41Sopenharmony_ci QUEUE_INIT(&head); 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci /* Process and filter out events */ 2481cb0ef41Sopenharmony_ci for (i = 0; i < numEvents; i++) { 2491cb0ef41Sopenharmony_ci flags = eventFlags[i]; 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci /* Ignore system events */ 2521cb0ef41Sopenharmony_ci if (flags & kFSEventsSystem) 2531cb0ef41Sopenharmony_ci continue; 2541cb0ef41Sopenharmony_ci 2551cb0ef41Sopenharmony_ci path = paths[i]; 2561cb0ef41Sopenharmony_ci len = strlen(path); 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci if (handle->realpath_len == 0) 2591cb0ef41Sopenharmony_ci continue; /* This should be unreachable */ 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci /* Filter out paths that are outside handle's request */ 2621cb0ef41Sopenharmony_ci if (len < handle->realpath_len) 2631cb0ef41Sopenharmony_ci continue; 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci /* Make sure that realpath actually named a directory, 2661cb0ef41Sopenharmony_ci * (unless watching root, which alone keeps a trailing slash on the realpath) 2671cb0ef41Sopenharmony_ci * or that we matched the whole string */ 2681cb0ef41Sopenharmony_ci if (handle->realpath_len != len && 2691cb0ef41Sopenharmony_ci handle->realpath_len > 1 && 2701cb0ef41Sopenharmony_ci path[handle->realpath_len] != '/') 2711cb0ef41Sopenharmony_ci continue; 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci if (memcmp(path, handle->realpath, handle->realpath_len) != 0) 2741cb0ef41Sopenharmony_ci continue; 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) { 2771cb0ef41Sopenharmony_ci /* Remove common prefix, unless the watched folder is "/" */ 2781cb0ef41Sopenharmony_ci path += handle->realpath_len; 2791cb0ef41Sopenharmony_ci len -= handle->realpath_len; 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci /* Ignore events with path equal to directory itself */ 2821cb0ef41Sopenharmony_ci if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir)) 2831cb0ef41Sopenharmony_ci continue; 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci if (len == 0) { 2861cb0ef41Sopenharmony_ci /* Since we're using fsevents to watch the file itself, 2871cb0ef41Sopenharmony_ci * realpath == path, and we now need to get the basename of the file back 2881cb0ef41Sopenharmony_ci * (for commonality with other codepaths and platforms). */ 2891cb0ef41Sopenharmony_ci while (len < handle->realpath_len && path[-1] != '/') { 2901cb0ef41Sopenharmony_ci path--; 2911cb0ef41Sopenharmony_ci len++; 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci /* Created and Removed seem to be always set, but don't make sense */ 2941cb0ef41Sopenharmony_ci flags &= ~kFSEventsRenamed; 2951cb0ef41Sopenharmony_ci } else { 2961cb0ef41Sopenharmony_ci /* Skip forward slash */ 2971cb0ef41Sopenharmony_ci path++; 2981cb0ef41Sopenharmony_ci len--; 2991cb0ef41Sopenharmony_ci } 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci /* Do not emit events from subdirectories (without option set) */ 3031cb0ef41Sopenharmony_ci if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') { 3041cb0ef41Sopenharmony_ci pos = strchr(path + 1, '/'); 3051cb0ef41Sopenharmony_ci if (pos != NULL) 3061cb0ef41Sopenharmony_ci continue; 3071cb0ef41Sopenharmony_ci } 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_ci event = uv__malloc(sizeof(*event) + len); 3101cb0ef41Sopenharmony_ci if (event == NULL) 3111cb0ef41Sopenharmony_ci break; 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci memset(event, 0, sizeof(*event)); 3141cb0ef41Sopenharmony_ci memcpy(event->path, path, len + 1); 3151cb0ef41Sopenharmony_ci event->events = UV_RENAME; 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci if (0 == (flags & kFSEventsRenamed)) { 3181cb0ef41Sopenharmony_ci if (0 != (flags & kFSEventsModified) || 3191cb0ef41Sopenharmony_ci 0 == (flags & kFSEventStreamEventFlagItemIsDir)) 3201cb0ef41Sopenharmony_ci event->events = UV_CHANGE; 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&head, &event->member); 3241cb0ef41Sopenharmony_ci } 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci if (!QUEUE_EMPTY(&head)) 3271cb0ef41Sopenharmony_ci uv__fsevents_push_event(handle, &head, 0); 3281cb0ef41Sopenharmony_ci } 3291cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 3301cb0ef41Sopenharmony_ci} 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci/* Runs in CF thread */ 3341cb0ef41Sopenharmony_cistatic int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) { 3351cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 3361cb0ef41Sopenharmony_ci FSEventStreamContext ctx; 3371cb0ef41Sopenharmony_ci FSEventStreamRef ref; 3381cb0ef41Sopenharmony_ci CFAbsoluteTime latency; 3391cb0ef41Sopenharmony_ci FSEventStreamCreateFlags flags; 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci /* Initialize context */ 3421cb0ef41Sopenharmony_ci memset(&ctx, 0, sizeof(ctx)); 3431cb0ef41Sopenharmony_ci ctx.info = loop; 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci latency = 0.05; 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ci /* Explanation of selected flags: 3481cb0ef41Sopenharmony_ci * 1. NoDefer - without this flag, events that are happening continuously 3491cb0ef41Sopenharmony_ci * (i.e. each event is happening after time interval less than `latency`, 3501cb0ef41Sopenharmony_ci * counted from previous event), will be deferred and passed to callback 3511cb0ef41Sopenharmony_ci * once they'll either fill whole OS buffer, or when this continuous stream 3521cb0ef41Sopenharmony_ci * will stop (i.e. there'll be delay between events, bigger than 3531cb0ef41Sopenharmony_ci * `latency`). 3541cb0ef41Sopenharmony_ci * Specifying this flag will invoke callback after `latency` time passed 3551cb0ef41Sopenharmony_ci * since event. 3561cb0ef41Sopenharmony_ci * 2. FileEvents - fire callback for file changes too (by default it is firing 3571cb0ef41Sopenharmony_ci * it only for directory changes). 3581cb0ef41Sopenharmony_ci */ 3591cb0ef41Sopenharmony_ci flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents; 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci /* 3621cb0ef41Sopenharmony_ci * NOTE: It might sound like a good idea to remember last seen StreamEventId, 3631cb0ef41Sopenharmony_ci * but in reality one dir might have last StreamEventId less than, the other, 3641cb0ef41Sopenharmony_ci * that is being watched now. Which will cause FSEventStream API to report 3651cb0ef41Sopenharmony_ci * changes to files from the past. 3661cb0ef41Sopenharmony_ci */ 3671cb0ef41Sopenharmony_ci ref = pFSEventStreamCreate(NULL, 3681cb0ef41Sopenharmony_ci &uv__fsevents_event_cb, 3691cb0ef41Sopenharmony_ci &ctx, 3701cb0ef41Sopenharmony_ci paths, 3711cb0ef41Sopenharmony_ci kFSEventStreamEventIdSinceNow, 3721cb0ef41Sopenharmony_ci latency, 3731cb0ef41Sopenharmony_ci flags); 3741cb0ef41Sopenharmony_ci assert(ref != NULL); 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci state = loop->cf_state; 3771cb0ef41Sopenharmony_ci pFSEventStreamScheduleWithRunLoop(ref, 3781cb0ef41Sopenharmony_ci state->loop, 3791cb0ef41Sopenharmony_ci *pkCFRunLoopDefaultMode); 3801cb0ef41Sopenharmony_ci if (!pFSEventStreamStart(ref)) { 3811cb0ef41Sopenharmony_ci pFSEventStreamInvalidate(ref); 3821cb0ef41Sopenharmony_ci pFSEventStreamRelease(ref); 3831cb0ef41Sopenharmony_ci return UV_EMFILE; 3841cb0ef41Sopenharmony_ci } 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci state->fsevent_stream = ref; 3871cb0ef41Sopenharmony_ci return 0; 3881cb0ef41Sopenharmony_ci} 3891cb0ef41Sopenharmony_ci 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci/* Runs in CF thread */ 3921cb0ef41Sopenharmony_cistatic void uv__fsevents_destroy_stream(uv_loop_t* loop) { 3931cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 3941cb0ef41Sopenharmony_ci 3951cb0ef41Sopenharmony_ci state = loop->cf_state; 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci if (state->fsevent_stream == NULL) 3981cb0ef41Sopenharmony_ci return; 3991cb0ef41Sopenharmony_ci 4001cb0ef41Sopenharmony_ci /* Stop emitting events */ 4011cb0ef41Sopenharmony_ci pFSEventStreamStop(state->fsevent_stream); 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ci /* Release stream */ 4041cb0ef41Sopenharmony_ci pFSEventStreamInvalidate(state->fsevent_stream); 4051cb0ef41Sopenharmony_ci pFSEventStreamRelease(state->fsevent_stream); 4061cb0ef41Sopenharmony_ci state->fsevent_stream = NULL; 4071cb0ef41Sopenharmony_ci} 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci 4101cb0ef41Sopenharmony_ci/* Runs in CF thread, when there're new fsevent handles to add to stream */ 4111cb0ef41Sopenharmony_cistatic void uv__fsevents_reschedule(uv_fs_event_t* handle, 4121cb0ef41Sopenharmony_ci uv__cf_loop_signal_type_t type) { 4131cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 4141cb0ef41Sopenharmony_ci QUEUE* q; 4151cb0ef41Sopenharmony_ci uv_fs_event_t* curr; 4161cb0ef41Sopenharmony_ci CFArrayRef cf_paths; 4171cb0ef41Sopenharmony_ci CFStringRef* paths; 4181cb0ef41Sopenharmony_ci unsigned int i; 4191cb0ef41Sopenharmony_ci int err; 4201cb0ef41Sopenharmony_ci unsigned int path_count; 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci state = handle->loop->cf_state; 4231cb0ef41Sopenharmony_ci paths = NULL; 4241cb0ef41Sopenharmony_ci cf_paths = NULL; 4251cb0ef41Sopenharmony_ci err = 0; 4261cb0ef41Sopenharmony_ci /* NOTE: `i` is used in deallocation loop below */ 4271cb0ef41Sopenharmony_ci i = 0; 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci /* Optimization to prevent O(n^2) time spent when starting to watch 4301cb0ef41Sopenharmony_ci * many files simultaneously 4311cb0ef41Sopenharmony_ci */ 4321cb0ef41Sopenharmony_ci uv_mutex_lock(&state->fsevent_mutex); 4331cb0ef41Sopenharmony_ci if (state->fsevent_need_reschedule == 0) { 4341cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 4351cb0ef41Sopenharmony_ci goto final; 4361cb0ef41Sopenharmony_ci } 4371cb0ef41Sopenharmony_ci state->fsevent_need_reschedule = 0; 4381cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci /* Destroy previous FSEventStream */ 4411cb0ef41Sopenharmony_ci uv__fsevents_destroy_stream(handle->loop); 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci /* Any failure below will be a memory failure */ 4441cb0ef41Sopenharmony_ci err = UV_ENOMEM; 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci /* Create list of all watched paths */ 4471cb0ef41Sopenharmony_ci uv_mutex_lock(&state->fsevent_mutex); 4481cb0ef41Sopenharmony_ci path_count = state->fsevent_handle_count; 4491cb0ef41Sopenharmony_ci if (path_count != 0) { 4501cb0ef41Sopenharmony_ci paths = uv__malloc(sizeof(*paths) * path_count); 4511cb0ef41Sopenharmony_ci if (paths == NULL) { 4521cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 4531cb0ef41Sopenharmony_ci goto final; 4541cb0ef41Sopenharmony_ci } 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci q = &state->fsevent_handles; 4571cb0ef41Sopenharmony_ci for (; i < path_count; i++) { 4581cb0ef41Sopenharmony_ci q = QUEUE_NEXT(q); 4591cb0ef41Sopenharmony_ci assert(q != &state->fsevent_handles); 4601cb0ef41Sopenharmony_ci curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci assert(curr->realpath != NULL); 4631cb0ef41Sopenharmony_ci paths[i] = 4641cb0ef41Sopenharmony_ci pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath); 4651cb0ef41Sopenharmony_ci if (paths[i] == NULL) { 4661cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 4671cb0ef41Sopenharmony_ci goto final; 4681cb0ef41Sopenharmony_ci } 4691cb0ef41Sopenharmony_ci } 4701cb0ef41Sopenharmony_ci } 4711cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 4721cb0ef41Sopenharmony_ci err = 0; 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ci if (path_count != 0) { 4751cb0ef41Sopenharmony_ci /* Create new FSEventStream */ 4761cb0ef41Sopenharmony_ci cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL); 4771cb0ef41Sopenharmony_ci if (cf_paths == NULL) { 4781cb0ef41Sopenharmony_ci err = UV_ENOMEM; 4791cb0ef41Sopenharmony_ci goto final; 4801cb0ef41Sopenharmony_ci } 4811cb0ef41Sopenharmony_ci err = uv__fsevents_create_stream(handle->loop, cf_paths); 4821cb0ef41Sopenharmony_ci } 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_cifinal: 4851cb0ef41Sopenharmony_ci /* Deallocate all paths in case of failure */ 4861cb0ef41Sopenharmony_ci if (err != 0) { 4871cb0ef41Sopenharmony_ci if (cf_paths == NULL) { 4881cb0ef41Sopenharmony_ci while (i != 0) 4891cb0ef41Sopenharmony_ci pCFRelease(paths[--i]); 4901cb0ef41Sopenharmony_ci uv__free(paths); 4911cb0ef41Sopenharmony_ci } else { 4921cb0ef41Sopenharmony_ci /* CFArray takes ownership of both strings and original C-array */ 4931cb0ef41Sopenharmony_ci pCFRelease(cf_paths); 4941cb0ef41Sopenharmony_ci } 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci /* Broadcast error to all handles */ 4971cb0ef41Sopenharmony_ci uv_mutex_lock(&state->fsevent_mutex); 4981cb0ef41Sopenharmony_ci QUEUE_FOREACH(q, &state->fsevent_handles) { 4991cb0ef41Sopenharmony_ci curr = QUEUE_DATA(q, uv_fs_event_t, cf_member); 5001cb0ef41Sopenharmony_ci uv__fsevents_push_event(curr, NULL, err); 5011cb0ef41Sopenharmony_ci } 5021cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 5031cb0ef41Sopenharmony_ci } 5041cb0ef41Sopenharmony_ci 5051cb0ef41Sopenharmony_ci /* 5061cb0ef41Sopenharmony_ci * Main thread will block until the removal of handle from the list, 5071cb0ef41Sopenharmony_ci * we must tell it when we're ready. 5081cb0ef41Sopenharmony_ci * 5091cb0ef41Sopenharmony_ci * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` 5101cb0ef41Sopenharmony_ci */ 5111cb0ef41Sopenharmony_ci if (type == kUVCFLoopSignalClosing) 5121cb0ef41Sopenharmony_ci uv_sem_post(&state->fsevent_sem); 5131cb0ef41Sopenharmony_ci} 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_cistatic int uv__fsevents_global_init(void) { 5171cb0ef41Sopenharmony_ci static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER; 5181cb0ef41Sopenharmony_ci static void* core_foundation_handle; 5191cb0ef41Sopenharmony_ci static void* core_services_handle; 5201cb0ef41Sopenharmony_ci int err; 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_ci err = 0; 5231cb0ef41Sopenharmony_ci pthread_mutex_lock(&global_init_mutex); 5241cb0ef41Sopenharmony_ci if (core_foundation_handle != NULL) 5251cb0ef41Sopenharmony_ci goto out; 5261cb0ef41Sopenharmony_ci 5271cb0ef41Sopenharmony_ci /* The libraries are never unloaded because we currently don't have a good 5281cb0ef41Sopenharmony_ci * mechanism for keeping a reference count. It's unlikely to be an issue 5291cb0ef41Sopenharmony_ci * but if it ever becomes one, we can turn the dynamic library handles into 5301cb0ef41Sopenharmony_ci * per-event loop properties and have the dynamic linker keep track for us. 5311cb0ef41Sopenharmony_ci */ 5321cb0ef41Sopenharmony_ci err = UV_ENOSYS; 5331cb0ef41Sopenharmony_ci core_foundation_handle = dlopen("/System/Library/Frameworks/" 5341cb0ef41Sopenharmony_ci "CoreFoundation.framework/" 5351cb0ef41Sopenharmony_ci "Versions/A/CoreFoundation", 5361cb0ef41Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL); 5371cb0ef41Sopenharmony_ci if (core_foundation_handle == NULL) 5381cb0ef41Sopenharmony_ci goto out; 5391cb0ef41Sopenharmony_ci 5401cb0ef41Sopenharmony_ci core_services_handle = dlopen("/System/Library/Frameworks/" 5411cb0ef41Sopenharmony_ci "CoreServices.framework/" 5421cb0ef41Sopenharmony_ci "Versions/A/CoreServices", 5431cb0ef41Sopenharmony_ci RTLD_LAZY | RTLD_LOCAL); 5441cb0ef41Sopenharmony_ci if (core_services_handle == NULL) 5451cb0ef41Sopenharmony_ci goto out; 5461cb0ef41Sopenharmony_ci 5471cb0ef41Sopenharmony_ci err = UV_ENOENT; 5481cb0ef41Sopenharmony_ci#define V(handle, symbol) \ 5491cb0ef41Sopenharmony_ci do { \ 5501cb0ef41Sopenharmony_ci *(void **)(&p ## symbol) = dlsym((handle), #symbol); \ 5511cb0ef41Sopenharmony_ci if (p ## symbol == NULL) \ 5521cb0ef41Sopenharmony_ci goto out; \ 5531cb0ef41Sopenharmony_ci } \ 5541cb0ef41Sopenharmony_ci while (0) 5551cb0ef41Sopenharmony_ci V(core_foundation_handle, CFArrayCreate); 5561cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRelease); 5571cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopAddSource); 5581cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopGetCurrent); 5591cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopRemoveSource); 5601cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopRun); 5611cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopSourceCreate); 5621cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopSourceSignal); 5631cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopStop); 5641cb0ef41Sopenharmony_ci V(core_foundation_handle, CFRunLoopWakeUp); 5651cb0ef41Sopenharmony_ci V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation); 5661cb0ef41Sopenharmony_ci V(core_foundation_handle, CFStringGetSystemEncoding); 5671cb0ef41Sopenharmony_ci V(core_foundation_handle, kCFRunLoopDefaultMode); 5681cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamCreate); 5691cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamFlushSync); 5701cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamInvalidate); 5711cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamRelease); 5721cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamScheduleWithRunLoop); 5731cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamStart); 5741cb0ef41Sopenharmony_ci V(core_services_handle, FSEventStreamStop); 5751cb0ef41Sopenharmony_ci#undef V 5761cb0ef41Sopenharmony_ci err = 0; 5771cb0ef41Sopenharmony_ci 5781cb0ef41Sopenharmony_ciout: 5791cb0ef41Sopenharmony_ci if (err && core_services_handle != NULL) { 5801cb0ef41Sopenharmony_ci dlclose(core_services_handle); 5811cb0ef41Sopenharmony_ci core_services_handle = NULL; 5821cb0ef41Sopenharmony_ci } 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci if (err && core_foundation_handle != NULL) { 5851cb0ef41Sopenharmony_ci dlclose(core_foundation_handle); 5861cb0ef41Sopenharmony_ci core_foundation_handle = NULL; 5871cb0ef41Sopenharmony_ci } 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ci pthread_mutex_unlock(&global_init_mutex); 5901cb0ef41Sopenharmony_ci return err; 5911cb0ef41Sopenharmony_ci} 5921cb0ef41Sopenharmony_ci 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci/* Runs in UV loop */ 5951cb0ef41Sopenharmony_cistatic int uv__fsevents_loop_init(uv_loop_t* loop) { 5961cb0ef41Sopenharmony_ci CFRunLoopSourceContext ctx; 5971cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 5981cb0ef41Sopenharmony_ci pthread_attr_t attr; 5991cb0ef41Sopenharmony_ci int err; 6001cb0ef41Sopenharmony_ci 6011cb0ef41Sopenharmony_ci if (loop->cf_state != NULL) 6021cb0ef41Sopenharmony_ci return 0; 6031cb0ef41Sopenharmony_ci 6041cb0ef41Sopenharmony_ci err = uv__fsevents_global_init(); 6051cb0ef41Sopenharmony_ci if (err) 6061cb0ef41Sopenharmony_ci return err; 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_ci state = uv__calloc(1, sizeof(*state)); 6091cb0ef41Sopenharmony_ci if (state == NULL) 6101cb0ef41Sopenharmony_ci return UV_ENOMEM; 6111cb0ef41Sopenharmony_ci 6121cb0ef41Sopenharmony_ci err = uv_mutex_init(&loop->cf_mutex); 6131cb0ef41Sopenharmony_ci if (err) 6141cb0ef41Sopenharmony_ci goto fail_mutex_init; 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_ci err = uv_sem_init(&loop->cf_sem, 0); 6171cb0ef41Sopenharmony_ci if (err) 6181cb0ef41Sopenharmony_ci goto fail_sem_init; 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_ci QUEUE_INIT(&loop->cf_signals); 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci err = uv_sem_init(&state->fsevent_sem, 0); 6231cb0ef41Sopenharmony_ci if (err) 6241cb0ef41Sopenharmony_ci goto fail_fsevent_sem_init; 6251cb0ef41Sopenharmony_ci 6261cb0ef41Sopenharmony_ci err = uv_mutex_init(&state->fsevent_mutex); 6271cb0ef41Sopenharmony_ci if (err) 6281cb0ef41Sopenharmony_ci goto fail_fsevent_mutex_init; 6291cb0ef41Sopenharmony_ci 6301cb0ef41Sopenharmony_ci QUEUE_INIT(&state->fsevent_handles); 6311cb0ef41Sopenharmony_ci state->fsevent_need_reschedule = 0; 6321cb0ef41Sopenharmony_ci state->fsevent_handle_count = 0; 6331cb0ef41Sopenharmony_ci 6341cb0ef41Sopenharmony_ci memset(&ctx, 0, sizeof(ctx)); 6351cb0ef41Sopenharmony_ci ctx.info = loop; 6361cb0ef41Sopenharmony_ci ctx.perform = uv__cf_loop_cb; 6371cb0ef41Sopenharmony_ci state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx); 6381cb0ef41Sopenharmony_ci if (state->signal_source == NULL) { 6391cb0ef41Sopenharmony_ci err = UV_ENOMEM; 6401cb0ef41Sopenharmony_ci goto fail_signal_source_create; 6411cb0ef41Sopenharmony_ci } 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci if (pthread_attr_init(&attr)) 6441cb0ef41Sopenharmony_ci abort(); 6451cb0ef41Sopenharmony_ci 6461cb0ef41Sopenharmony_ci if (pthread_attr_setstacksize(&attr, uv__thread_stack_size())) 6471cb0ef41Sopenharmony_ci abort(); 6481cb0ef41Sopenharmony_ci 6491cb0ef41Sopenharmony_ci loop->cf_state = state; 6501cb0ef41Sopenharmony_ci 6511cb0ef41Sopenharmony_ci /* uv_thread_t is an alias for pthread_t. */ 6521cb0ef41Sopenharmony_ci err = UV__ERR(pthread_create(&loop->cf_thread, &attr, uv__cf_loop_runner, loop)); 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci if (pthread_attr_destroy(&attr)) 6551cb0ef41Sopenharmony_ci abort(); 6561cb0ef41Sopenharmony_ci 6571cb0ef41Sopenharmony_ci if (err) 6581cb0ef41Sopenharmony_ci goto fail_thread_create; 6591cb0ef41Sopenharmony_ci 6601cb0ef41Sopenharmony_ci /* Synchronize threads */ 6611cb0ef41Sopenharmony_ci uv_sem_wait(&loop->cf_sem); 6621cb0ef41Sopenharmony_ci return 0; 6631cb0ef41Sopenharmony_ci 6641cb0ef41Sopenharmony_cifail_thread_create: 6651cb0ef41Sopenharmony_ci loop->cf_state = NULL; 6661cb0ef41Sopenharmony_ci 6671cb0ef41Sopenharmony_cifail_signal_source_create: 6681cb0ef41Sopenharmony_ci uv_mutex_destroy(&state->fsevent_mutex); 6691cb0ef41Sopenharmony_ci 6701cb0ef41Sopenharmony_cifail_fsevent_mutex_init: 6711cb0ef41Sopenharmony_ci uv_sem_destroy(&state->fsevent_sem); 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_cifail_fsevent_sem_init: 6741cb0ef41Sopenharmony_ci uv_sem_destroy(&loop->cf_sem); 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_cifail_sem_init: 6771cb0ef41Sopenharmony_ci uv_mutex_destroy(&loop->cf_mutex); 6781cb0ef41Sopenharmony_ci 6791cb0ef41Sopenharmony_cifail_mutex_init: 6801cb0ef41Sopenharmony_ci uv__free(state); 6811cb0ef41Sopenharmony_ci return err; 6821cb0ef41Sopenharmony_ci} 6831cb0ef41Sopenharmony_ci 6841cb0ef41Sopenharmony_ci 6851cb0ef41Sopenharmony_ci/* Runs in UV loop */ 6861cb0ef41Sopenharmony_civoid uv__fsevents_loop_delete(uv_loop_t* loop) { 6871cb0ef41Sopenharmony_ci uv__cf_loop_signal_t* s; 6881cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 6891cb0ef41Sopenharmony_ci QUEUE* q; 6901cb0ef41Sopenharmony_ci 6911cb0ef41Sopenharmony_ci if (loop->cf_state == NULL) 6921cb0ef41Sopenharmony_ci return; 6931cb0ef41Sopenharmony_ci 6941cb0ef41Sopenharmony_ci if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0) 6951cb0ef41Sopenharmony_ci abort(); 6961cb0ef41Sopenharmony_ci 6971cb0ef41Sopenharmony_ci uv_thread_join(&loop->cf_thread); 6981cb0ef41Sopenharmony_ci uv_sem_destroy(&loop->cf_sem); 6991cb0ef41Sopenharmony_ci uv_mutex_destroy(&loop->cf_mutex); 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_ci /* Free any remaining data */ 7021cb0ef41Sopenharmony_ci while (!QUEUE_EMPTY(&loop->cf_signals)) { 7031cb0ef41Sopenharmony_ci q = QUEUE_HEAD(&loop->cf_signals); 7041cb0ef41Sopenharmony_ci s = QUEUE_DATA(q, uv__cf_loop_signal_t, member); 7051cb0ef41Sopenharmony_ci QUEUE_REMOVE(q); 7061cb0ef41Sopenharmony_ci uv__free(s); 7071cb0ef41Sopenharmony_ci } 7081cb0ef41Sopenharmony_ci 7091cb0ef41Sopenharmony_ci /* Destroy state */ 7101cb0ef41Sopenharmony_ci state = loop->cf_state; 7111cb0ef41Sopenharmony_ci uv_sem_destroy(&state->fsevent_sem); 7121cb0ef41Sopenharmony_ci uv_mutex_destroy(&state->fsevent_mutex); 7131cb0ef41Sopenharmony_ci pCFRelease(state->signal_source); 7141cb0ef41Sopenharmony_ci uv__free(state); 7151cb0ef41Sopenharmony_ci loop->cf_state = NULL; 7161cb0ef41Sopenharmony_ci} 7171cb0ef41Sopenharmony_ci 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ci/* Runs in CF thread. This is the CF loop's body */ 7201cb0ef41Sopenharmony_cistatic void* uv__cf_loop_runner(void* arg) { 7211cb0ef41Sopenharmony_ci uv_loop_t* loop; 7221cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ci loop = arg; 7251cb0ef41Sopenharmony_ci state = loop->cf_state; 7261cb0ef41Sopenharmony_ci state->loop = pCFRunLoopGetCurrent(); 7271cb0ef41Sopenharmony_ci 7281cb0ef41Sopenharmony_ci pCFRunLoopAddSource(state->loop, 7291cb0ef41Sopenharmony_ci state->signal_source, 7301cb0ef41Sopenharmony_ci *pkCFRunLoopDefaultMode); 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci uv_sem_post(&loop->cf_sem); 7331cb0ef41Sopenharmony_ci 7341cb0ef41Sopenharmony_ci pCFRunLoopRun(); 7351cb0ef41Sopenharmony_ci pCFRunLoopRemoveSource(state->loop, 7361cb0ef41Sopenharmony_ci state->signal_source, 7371cb0ef41Sopenharmony_ci *pkCFRunLoopDefaultMode); 7381cb0ef41Sopenharmony_ci 7391cb0ef41Sopenharmony_ci state->loop = NULL; 7401cb0ef41Sopenharmony_ci 7411cb0ef41Sopenharmony_ci return NULL; 7421cb0ef41Sopenharmony_ci} 7431cb0ef41Sopenharmony_ci 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci/* Runs in CF thread, executed after `uv__cf_loop_signal()` */ 7461cb0ef41Sopenharmony_cistatic void uv__cf_loop_cb(void* arg) { 7471cb0ef41Sopenharmony_ci uv_loop_t* loop; 7481cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 7491cb0ef41Sopenharmony_ci QUEUE* item; 7501cb0ef41Sopenharmony_ci QUEUE split_head; 7511cb0ef41Sopenharmony_ci uv__cf_loop_signal_t* s; 7521cb0ef41Sopenharmony_ci 7531cb0ef41Sopenharmony_ci loop = arg; 7541cb0ef41Sopenharmony_ci state = loop->cf_state; 7551cb0ef41Sopenharmony_ci 7561cb0ef41Sopenharmony_ci uv_mutex_lock(&loop->cf_mutex); 7571cb0ef41Sopenharmony_ci QUEUE_MOVE(&loop->cf_signals, &split_head); 7581cb0ef41Sopenharmony_ci uv_mutex_unlock(&loop->cf_mutex); 7591cb0ef41Sopenharmony_ci 7601cb0ef41Sopenharmony_ci while (!QUEUE_EMPTY(&split_head)) { 7611cb0ef41Sopenharmony_ci item = QUEUE_HEAD(&split_head); 7621cb0ef41Sopenharmony_ci QUEUE_REMOVE(item); 7631cb0ef41Sopenharmony_ci 7641cb0ef41Sopenharmony_ci s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); 7651cb0ef41Sopenharmony_ci 7661cb0ef41Sopenharmony_ci /* This was a termination signal */ 7671cb0ef41Sopenharmony_ci if (s->handle == NULL) 7681cb0ef41Sopenharmony_ci pCFRunLoopStop(state->loop); 7691cb0ef41Sopenharmony_ci else 7701cb0ef41Sopenharmony_ci uv__fsevents_reschedule(s->handle, s->type); 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_ci uv__free(s); 7731cb0ef41Sopenharmony_ci } 7741cb0ef41Sopenharmony_ci} 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ci 7771cb0ef41Sopenharmony_ci/* Runs in UV loop to notify CF thread */ 7781cb0ef41Sopenharmony_ciint uv__cf_loop_signal(uv_loop_t* loop, 7791cb0ef41Sopenharmony_ci uv_fs_event_t* handle, 7801cb0ef41Sopenharmony_ci uv__cf_loop_signal_type_t type) { 7811cb0ef41Sopenharmony_ci uv__cf_loop_signal_t* item; 7821cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci item = uv__malloc(sizeof(*item)); 7851cb0ef41Sopenharmony_ci if (item == NULL) 7861cb0ef41Sopenharmony_ci return UV_ENOMEM; 7871cb0ef41Sopenharmony_ci 7881cb0ef41Sopenharmony_ci item->handle = handle; 7891cb0ef41Sopenharmony_ci item->type = type; 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_ci uv_mutex_lock(&loop->cf_mutex); 7921cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); 7931cb0ef41Sopenharmony_ci 7941cb0ef41Sopenharmony_ci state = loop->cf_state; 7951cb0ef41Sopenharmony_ci assert(state != NULL); 7961cb0ef41Sopenharmony_ci pCFRunLoopSourceSignal(state->signal_source); 7971cb0ef41Sopenharmony_ci pCFRunLoopWakeUp(state->loop); 7981cb0ef41Sopenharmony_ci 7991cb0ef41Sopenharmony_ci uv_mutex_unlock(&loop->cf_mutex); 8001cb0ef41Sopenharmony_ci 8011cb0ef41Sopenharmony_ci return 0; 8021cb0ef41Sopenharmony_ci} 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ci 8051cb0ef41Sopenharmony_ci/* Runs in UV loop to initialize handle */ 8061cb0ef41Sopenharmony_ciint uv__fsevents_init(uv_fs_event_t* handle) { 8071cb0ef41Sopenharmony_ci int err; 8081cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 8091cb0ef41Sopenharmony_ci 8101cb0ef41Sopenharmony_ci err = uv__fsevents_loop_init(handle->loop); 8111cb0ef41Sopenharmony_ci if (err) 8121cb0ef41Sopenharmony_ci return err; 8131cb0ef41Sopenharmony_ci 8141cb0ef41Sopenharmony_ci /* Get absolute path to file */ 8151cb0ef41Sopenharmony_ci handle->realpath = realpath(handle->path, NULL); 8161cb0ef41Sopenharmony_ci if (handle->realpath == NULL) 8171cb0ef41Sopenharmony_ci return UV__ERR(errno); 8181cb0ef41Sopenharmony_ci handle->realpath_len = strlen(handle->realpath); 8191cb0ef41Sopenharmony_ci 8201cb0ef41Sopenharmony_ci /* Initialize event queue */ 8211cb0ef41Sopenharmony_ci QUEUE_INIT(&handle->cf_events); 8221cb0ef41Sopenharmony_ci handle->cf_error = 0; 8231cb0ef41Sopenharmony_ci 8241cb0ef41Sopenharmony_ci /* 8251cb0ef41Sopenharmony_ci * Events will occur in other thread. 8261cb0ef41Sopenharmony_ci * Initialize callback for getting them back into event loop's thread 8271cb0ef41Sopenharmony_ci */ 8281cb0ef41Sopenharmony_ci handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb)); 8291cb0ef41Sopenharmony_ci if (handle->cf_cb == NULL) { 8301cb0ef41Sopenharmony_ci err = UV_ENOMEM; 8311cb0ef41Sopenharmony_ci goto fail_cf_cb_malloc; 8321cb0ef41Sopenharmony_ci } 8331cb0ef41Sopenharmony_ci 8341cb0ef41Sopenharmony_ci handle->cf_cb->data = handle; 8351cb0ef41Sopenharmony_ci uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); 8361cb0ef41Sopenharmony_ci handle->cf_cb->flags |= UV_HANDLE_INTERNAL; 8371cb0ef41Sopenharmony_ci uv_unref((uv_handle_t*) handle->cf_cb); 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_ci err = uv_mutex_init(&handle->cf_mutex); 8401cb0ef41Sopenharmony_ci if (err) 8411cb0ef41Sopenharmony_ci goto fail_cf_mutex_init; 8421cb0ef41Sopenharmony_ci 8431cb0ef41Sopenharmony_ci /* Insert handle into the list */ 8441cb0ef41Sopenharmony_ci state = handle->loop->cf_state; 8451cb0ef41Sopenharmony_ci uv_mutex_lock(&state->fsevent_mutex); 8461cb0ef41Sopenharmony_ci QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member); 8471cb0ef41Sopenharmony_ci state->fsevent_handle_count++; 8481cb0ef41Sopenharmony_ci state->fsevent_need_reschedule = 1; 8491cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_ci /* Reschedule FSEventStream */ 8521cb0ef41Sopenharmony_ci assert(handle != NULL); 8531cb0ef41Sopenharmony_ci err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular); 8541cb0ef41Sopenharmony_ci if (err) 8551cb0ef41Sopenharmony_ci goto fail_loop_signal; 8561cb0ef41Sopenharmony_ci 8571cb0ef41Sopenharmony_ci return 0; 8581cb0ef41Sopenharmony_ci 8591cb0ef41Sopenharmony_cifail_loop_signal: 8601cb0ef41Sopenharmony_ci uv_mutex_destroy(&handle->cf_mutex); 8611cb0ef41Sopenharmony_ci 8621cb0ef41Sopenharmony_cifail_cf_mutex_init: 8631cb0ef41Sopenharmony_ci uv__free(handle->cf_cb); 8641cb0ef41Sopenharmony_ci handle->cf_cb = NULL; 8651cb0ef41Sopenharmony_ci 8661cb0ef41Sopenharmony_cifail_cf_cb_malloc: 8671cb0ef41Sopenharmony_ci uv__free(handle->realpath); 8681cb0ef41Sopenharmony_ci handle->realpath = NULL; 8691cb0ef41Sopenharmony_ci handle->realpath_len = 0; 8701cb0ef41Sopenharmony_ci 8711cb0ef41Sopenharmony_ci return err; 8721cb0ef41Sopenharmony_ci} 8731cb0ef41Sopenharmony_ci 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci/* Runs in UV loop to de-initialize handle */ 8761cb0ef41Sopenharmony_ciint uv__fsevents_close(uv_fs_event_t* handle) { 8771cb0ef41Sopenharmony_ci int err; 8781cb0ef41Sopenharmony_ci uv__cf_loop_state_t* state; 8791cb0ef41Sopenharmony_ci 8801cb0ef41Sopenharmony_ci if (handle->cf_cb == NULL) 8811cb0ef41Sopenharmony_ci return UV_EINVAL; 8821cb0ef41Sopenharmony_ci 8831cb0ef41Sopenharmony_ci /* Remove handle from the list */ 8841cb0ef41Sopenharmony_ci state = handle->loop->cf_state; 8851cb0ef41Sopenharmony_ci uv_mutex_lock(&state->fsevent_mutex); 8861cb0ef41Sopenharmony_ci QUEUE_REMOVE(&handle->cf_member); 8871cb0ef41Sopenharmony_ci state->fsevent_handle_count--; 8881cb0ef41Sopenharmony_ci state->fsevent_need_reschedule = 1; 8891cb0ef41Sopenharmony_ci uv_mutex_unlock(&state->fsevent_mutex); 8901cb0ef41Sopenharmony_ci 8911cb0ef41Sopenharmony_ci /* Reschedule FSEventStream */ 8921cb0ef41Sopenharmony_ci assert(handle != NULL); 8931cb0ef41Sopenharmony_ci err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); 8941cb0ef41Sopenharmony_ci if (err) 8951cb0ef41Sopenharmony_ci return UV__ERR(err); 8961cb0ef41Sopenharmony_ci 8971cb0ef41Sopenharmony_ci /* Wait for deinitialization */ 8981cb0ef41Sopenharmony_ci uv_sem_wait(&state->fsevent_sem); 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_ci uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free); 9011cb0ef41Sopenharmony_ci handle->cf_cb = NULL; 9021cb0ef41Sopenharmony_ci 9031cb0ef41Sopenharmony_ci /* Free data in queue */ 9041cb0ef41Sopenharmony_ci UV__FSEVENTS_PROCESS(handle, { 9051cb0ef41Sopenharmony_ci /* NOP */ 9061cb0ef41Sopenharmony_ci }); 9071cb0ef41Sopenharmony_ci 9081cb0ef41Sopenharmony_ci uv_mutex_destroy(&handle->cf_mutex); 9091cb0ef41Sopenharmony_ci uv__free(handle->realpath); 9101cb0ef41Sopenharmony_ci handle->realpath = NULL; 9111cb0ef41Sopenharmony_ci handle->realpath_len = 0; 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_ci return 0; 9141cb0ef41Sopenharmony_ci} 9151cb0ef41Sopenharmony_ci 9161cb0ef41Sopenharmony_ci#endif /* TARGET_OS_IPHONE */ 917