fsevents.c 29 KB

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