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