1
0

fsevents.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  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. if (handle->realpath_len != len &&
  226. path[handle->realpath_len] != '/')
  227. /* Make sure that realpath actually named a directory,
  228. * or that we matched the whole string */
  229. continue;
  230. if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
  231. continue;
  232. if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
  233. /* Remove common prefix, unless the watched folder is "/" */
  234. path += handle->realpath_len;
  235. len -= handle->realpath_len;
  236. /* Ignore events with path equal to directory itself */
  237. if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
  238. continue;
  239. if (len == 0) {
  240. /* Since we're using fsevents to watch the file itself,
  241. * realpath == path, and we now need to get the basename of the file back
  242. * (for commonality with other codepaths and platforms). */
  243. while (len < handle->realpath_len && path[-1] != '/') {
  244. path--;
  245. len++;
  246. }
  247. /* Created and Removed seem to be always set, but don't make sense */
  248. flags &= ~kFSEventsRenamed;
  249. } else {
  250. /* Skip forward slash */
  251. path++;
  252. len--;
  253. }
  254. }
  255. /* Do not emit events from subdirectories (without option set) */
  256. if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
  257. pos = strchr(path + 1, '/');
  258. if (pos != NULL)
  259. continue;
  260. }
  261. event = uv__malloc(sizeof(*event) + len);
  262. if (event == NULL)
  263. break;
  264. memset(event, 0, sizeof(*event));
  265. memcpy(event->path, path, len + 1);
  266. event->events = UV_RENAME;
  267. if (0 == (flags & kFSEventsRenamed)) {
  268. if (0 != (flags & kFSEventsModified) ||
  269. 0 == (flags & kFSEventStreamEventFlagItemIsDir))
  270. event->events = UV_CHANGE;
  271. }
  272. QUEUE_INSERT_TAIL(&head, &event->member);
  273. }
  274. if (!QUEUE_EMPTY(&head))
  275. uv__fsevents_push_event(handle, &head, 0);
  276. }
  277. uv_mutex_unlock(&state->fsevent_mutex);
  278. }
  279. /* Runs in CF thread */
  280. static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
  281. uv__cf_loop_state_t* state;
  282. FSEventStreamContext ctx;
  283. FSEventStreamRef ref;
  284. CFAbsoluteTime latency;
  285. FSEventStreamCreateFlags flags;
  286. /* Initialize context */
  287. ctx.version = 0;
  288. ctx.info = loop;
  289. ctx.retain = NULL;
  290. ctx.release = NULL;
  291. ctx.copyDescription = NULL;
  292. latency = 0.05;
  293. /* Explanation of selected flags:
  294. * 1. NoDefer - without this flag, events that are happening continuously
  295. * (i.e. each event is happening after time interval less than `latency`,
  296. * counted from previous event), will be deferred and passed to callback
  297. * once they'll either fill whole OS buffer, or when this continuous stream
  298. * will stop (i.e. there'll be delay between events, bigger than
  299. * `latency`).
  300. * Specifying this flag will invoke callback after `latency` time passed
  301. * since event.
  302. * 2. FileEvents - fire callback for file changes too (by default it is firing
  303. * it only for directory changes).
  304. */
  305. flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
  306. /*
  307. * NOTE: It might sound like a good idea to remember last seen StreamEventId,
  308. * but in reality one dir might have last StreamEventId less than, the other,
  309. * that is being watched now. Which will cause FSEventStream API to report
  310. * changes to files from the past.
  311. */
  312. ref = pFSEventStreamCreate(NULL,
  313. &uv__fsevents_event_cb,
  314. &ctx,
  315. paths,
  316. kFSEventStreamEventIdSinceNow,
  317. latency,
  318. flags);
  319. assert(ref != NULL);
  320. state = loop->cf_state;
  321. pFSEventStreamScheduleWithRunLoop(ref,
  322. state->loop,
  323. *pkCFRunLoopDefaultMode);
  324. if (!pFSEventStreamStart(ref)) {
  325. pFSEventStreamInvalidate(ref);
  326. pFSEventStreamRelease(ref);
  327. return UV_EMFILE;
  328. }
  329. state->fsevent_stream = ref;
  330. return 0;
  331. }
  332. /* Runs in CF thread */
  333. static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
  334. uv__cf_loop_state_t* state;
  335. state = loop->cf_state;
  336. if (state->fsevent_stream == NULL)
  337. return;
  338. /* Stop emitting events */
  339. pFSEventStreamStop(state->fsevent_stream);
  340. /* Release stream */
  341. pFSEventStreamInvalidate(state->fsevent_stream);
  342. pFSEventStreamRelease(state->fsevent_stream);
  343. state->fsevent_stream = NULL;
  344. }
  345. /* Runs in CF thread, when there're new fsevent handles to add to stream */
  346. static void uv__fsevents_reschedule(uv_fs_event_t* handle,
  347. uv__cf_loop_signal_type_t type) {
  348. uv__cf_loop_state_t* state;
  349. QUEUE* q;
  350. uv_fs_event_t* curr;
  351. CFArrayRef cf_paths;
  352. CFStringRef* paths;
  353. unsigned int i;
  354. int err;
  355. unsigned int path_count;
  356. state = handle->loop->cf_state;
  357. paths = NULL;
  358. cf_paths = NULL;
  359. err = 0;
  360. /* NOTE: `i` is used in deallocation loop below */
  361. i = 0;
  362. /* Optimization to prevent O(n^2) time spent when starting to watch
  363. * many files simultaneously
  364. */
  365. uv_mutex_lock(&state->fsevent_mutex);
  366. if (state->fsevent_need_reschedule == 0) {
  367. uv_mutex_unlock(&state->fsevent_mutex);
  368. goto final;
  369. }
  370. state->fsevent_need_reschedule = 0;
  371. uv_mutex_unlock(&state->fsevent_mutex);
  372. /* Destroy previous FSEventStream */
  373. uv__fsevents_destroy_stream(handle->loop);
  374. /* Any failure below will be a memory failure */
  375. err = UV_ENOMEM;
  376. /* Create list of all watched paths */
  377. uv_mutex_lock(&state->fsevent_mutex);
  378. path_count = state->fsevent_handle_count;
  379. if (path_count != 0) {
  380. paths = uv__malloc(sizeof(*paths) * path_count);
  381. if (paths == NULL) {
  382. uv_mutex_unlock(&state->fsevent_mutex);
  383. goto final;
  384. }
  385. q = &state->fsevent_handles;
  386. for (; i < path_count; i++) {
  387. q = QUEUE_NEXT(q);
  388. assert(q != &state->fsevent_handles);
  389. curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
  390. assert(curr->realpath != NULL);
  391. paths[i] =
  392. pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
  393. if (paths[i] == NULL) {
  394. uv_mutex_unlock(&state->fsevent_mutex);
  395. goto final;
  396. }
  397. }
  398. }
  399. uv_mutex_unlock(&state->fsevent_mutex);
  400. err = 0;
  401. if (path_count != 0) {
  402. /* Create new FSEventStream */
  403. cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
  404. if (cf_paths == NULL) {
  405. err = UV_ENOMEM;
  406. goto final;
  407. }
  408. err = uv__fsevents_create_stream(handle->loop, cf_paths);
  409. }
  410. final:
  411. /* Deallocate all paths in case of failure */
  412. if (err != 0) {
  413. if (cf_paths == NULL) {
  414. while (i != 0)
  415. pCFRelease(paths[--i]);
  416. uv__free(paths);
  417. } else {
  418. /* CFArray takes ownership of both strings and original C-array */
  419. pCFRelease(cf_paths);
  420. }
  421. /* Broadcast error to all handles */
  422. uv_mutex_lock(&state->fsevent_mutex);
  423. QUEUE_FOREACH(q, &state->fsevent_handles) {
  424. curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
  425. uv__fsevents_push_event(curr, NULL, err);
  426. }
  427. uv_mutex_unlock(&state->fsevent_mutex);
  428. }
  429. /*
  430. * Main thread will block until the removal of handle from the list,
  431. * we must tell it when we're ready.
  432. *
  433. * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
  434. */
  435. if (type == kUVCFLoopSignalClosing)
  436. uv_sem_post(&state->fsevent_sem);
  437. }
  438. static int uv__fsevents_global_init(void) {
  439. static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
  440. static void* core_foundation_handle;
  441. static void* core_services_handle;
  442. int err;
  443. err = 0;
  444. pthread_mutex_lock(&global_init_mutex);
  445. if (core_foundation_handle != NULL)
  446. goto out;
  447. /* The libraries are never unloaded because we currently don't have a good
  448. * mechanism for keeping a reference count. It's unlikely to be an issue
  449. * but if it ever becomes one, we can turn the dynamic library handles into
  450. * per-event loop properties and have the dynamic linker keep track for us.
  451. */
  452. err = UV_ENOSYS;
  453. core_foundation_handle = dlopen("/System/Library/Frameworks/"
  454. "CoreFoundation.framework/"
  455. "Versions/A/CoreFoundation",
  456. RTLD_LAZY | RTLD_LOCAL);
  457. if (core_foundation_handle == NULL)
  458. goto out;
  459. core_services_handle = dlopen("/System/Library/Frameworks/"
  460. "CoreServices.framework/"
  461. "Versions/A/CoreServices",
  462. RTLD_LAZY | RTLD_LOCAL);
  463. if (core_services_handle == NULL)
  464. goto out;
  465. err = UV_ENOENT;
  466. #define V(handle, symbol) \
  467. do { \
  468. *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
  469. if (p ## symbol == NULL) \
  470. goto out; \
  471. } \
  472. while (0)
  473. V(core_foundation_handle, CFArrayCreate);
  474. V(core_foundation_handle, CFRelease);
  475. V(core_foundation_handle, CFRunLoopAddSource);
  476. V(core_foundation_handle, CFRunLoopGetCurrent);
  477. V(core_foundation_handle, CFRunLoopRemoveSource);
  478. V(core_foundation_handle, CFRunLoopRun);
  479. V(core_foundation_handle, CFRunLoopSourceCreate);
  480. V(core_foundation_handle, CFRunLoopSourceSignal);
  481. V(core_foundation_handle, CFRunLoopStop);
  482. V(core_foundation_handle, CFRunLoopWakeUp);
  483. V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
  484. V(core_foundation_handle, CFStringGetSystemEncoding);
  485. V(core_foundation_handle, kCFRunLoopDefaultMode);
  486. V(core_services_handle, FSEventStreamCreate);
  487. V(core_services_handle, FSEventStreamFlushSync);
  488. V(core_services_handle, FSEventStreamInvalidate);
  489. V(core_services_handle, FSEventStreamRelease);
  490. V(core_services_handle, FSEventStreamScheduleWithRunLoop);
  491. V(core_services_handle, FSEventStreamStart);
  492. V(core_services_handle, FSEventStreamStop);
  493. #undef V
  494. err = 0;
  495. out:
  496. if (err && core_services_handle != NULL) {
  497. dlclose(core_services_handle);
  498. core_services_handle = NULL;
  499. }
  500. if (err && core_foundation_handle != NULL) {
  501. dlclose(core_foundation_handle);
  502. core_foundation_handle = NULL;
  503. }
  504. pthread_mutex_unlock(&global_init_mutex);
  505. return err;
  506. }
  507. /* Runs in UV loop */
  508. static int uv__fsevents_loop_init(uv_loop_t* loop) {
  509. CFRunLoopSourceContext ctx;
  510. uv__cf_loop_state_t* state;
  511. pthread_attr_t attr_storage;
  512. pthread_attr_t* attr;
  513. int err;
  514. if (loop->cf_state != NULL)
  515. return 0;
  516. err = uv__fsevents_global_init();
  517. if (err)
  518. return err;
  519. state = uv__calloc(1, sizeof(*state));
  520. if (state == NULL)
  521. return UV_ENOMEM;
  522. err = uv_mutex_init(&loop->cf_mutex);
  523. if (err)
  524. goto fail_mutex_init;
  525. err = uv_sem_init(&loop->cf_sem, 0);
  526. if (err)
  527. goto fail_sem_init;
  528. QUEUE_INIT(&loop->cf_signals);
  529. err = uv_sem_init(&state->fsevent_sem, 0);
  530. if (err)
  531. goto fail_fsevent_sem_init;
  532. err = uv_mutex_init(&state->fsevent_mutex);
  533. if (err)
  534. goto fail_fsevent_mutex_init;
  535. QUEUE_INIT(&state->fsevent_handles);
  536. state->fsevent_need_reschedule = 0;
  537. state->fsevent_handle_count = 0;
  538. memset(&ctx, 0, sizeof(ctx));
  539. ctx.info = loop;
  540. ctx.perform = uv__cf_loop_cb;
  541. state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
  542. if (state->signal_source == NULL) {
  543. err = UV_ENOMEM;
  544. goto fail_signal_source_create;
  545. }
  546. /* In the unlikely event that pthread_attr_init() fails, create the thread
  547. * with the default stack size. We'll use a little more address space but
  548. * that in itself is not a fatal error.
  549. */
  550. attr = &attr_storage;
  551. if (pthread_attr_init(attr))
  552. attr = NULL;
  553. if (attr != NULL)
  554. if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
  555. abort();
  556. loop->cf_state = state;
  557. /* uv_thread_t is an alias for pthread_t. */
  558. err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop));
  559. if (attr != NULL)
  560. pthread_attr_destroy(attr);
  561. if (err)
  562. goto fail_thread_create;
  563. /* Synchronize threads */
  564. uv_sem_wait(&loop->cf_sem);
  565. return 0;
  566. fail_thread_create:
  567. loop->cf_state = NULL;
  568. fail_signal_source_create:
  569. uv_mutex_destroy(&state->fsevent_mutex);
  570. fail_fsevent_mutex_init:
  571. uv_sem_destroy(&state->fsevent_sem);
  572. fail_fsevent_sem_init:
  573. uv_sem_destroy(&loop->cf_sem);
  574. fail_sem_init:
  575. uv_mutex_destroy(&loop->cf_mutex);
  576. fail_mutex_init:
  577. uv__free(state);
  578. return err;
  579. }
  580. /* Runs in UV loop */
  581. void uv__fsevents_loop_delete(uv_loop_t* loop) {
  582. uv__cf_loop_signal_t* s;
  583. uv__cf_loop_state_t* state;
  584. QUEUE* q;
  585. if (loop->cf_state == NULL)
  586. return;
  587. if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
  588. abort();
  589. uv_thread_join(&loop->cf_thread);
  590. uv_sem_destroy(&loop->cf_sem);
  591. uv_mutex_destroy(&loop->cf_mutex);
  592. /* Free any remaining data */
  593. while (!QUEUE_EMPTY(&loop->cf_signals)) {
  594. q = QUEUE_HEAD(&loop->cf_signals);
  595. s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
  596. QUEUE_REMOVE(q);
  597. uv__free(s);
  598. }
  599. /* Destroy state */
  600. state = loop->cf_state;
  601. uv_sem_destroy(&state->fsevent_sem);
  602. uv_mutex_destroy(&state->fsevent_mutex);
  603. pCFRelease(state->signal_source);
  604. uv__free(state);
  605. loop->cf_state = NULL;
  606. }
  607. /* Runs in CF thread. This is the CF loop's body */
  608. static void* uv__cf_loop_runner(void* arg) {
  609. uv_loop_t* loop;
  610. uv__cf_loop_state_t* state;
  611. loop = arg;
  612. state = loop->cf_state;
  613. state->loop = pCFRunLoopGetCurrent();
  614. pCFRunLoopAddSource(state->loop,
  615. state->signal_source,
  616. *pkCFRunLoopDefaultMode);
  617. uv_sem_post(&loop->cf_sem);
  618. pCFRunLoopRun();
  619. pCFRunLoopRemoveSource(state->loop,
  620. state->signal_source,
  621. *pkCFRunLoopDefaultMode);
  622. return NULL;
  623. }
  624. /* Runs in CF thread, executed after `uv__cf_loop_signal()` */
  625. static void uv__cf_loop_cb(void* arg) {
  626. uv_loop_t* loop;
  627. uv__cf_loop_state_t* state;
  628. QUEUE* item;
  629. QUEUE split_head;
  630. uv__cf_loop_signal_t* s;
  631. loop = arg;
  632. state = loop->cf_state;
  633. uv_mutex_lock(&loop->cf_mutex);
  634. QUEUE_MOVE(&loop->cf_signals, &split_head);
  635. uv_mutex_unlock(&loop->cf_mutex);
  636. while (!QUEUE_EMPTY(&split_head)) {
  637. item = QUEUE_HEAD(&split_head);
  638. QUEUE_REMOVE(item);
  639. s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
  640. /* This was a termination signal */
  641. if (s->handle == NULL)
  642. pCFRunLoopStop(state->loop);
  643. else
  644. uv__fsevents_reschedule(s->handle, s->type);
  645. uv__free(s);
  646. }
  647. }
  648. /* Runs in UV loop to notify CF thread */
  649. int uv__cf_loop_signal(uv_loop_t* loop,
  650. uv_fs_event_t* handle,
  651. uv__cf_loop_signal_type_t type) {
  652. uv__cf_loop_signal_t* item;
  653. uv__cf_loop_state_t* state;
  654. item = uv__malloc(sizeof(*item));
  655. if (item == NULL)
  656. return UV_ENOMEM;
  657. item->handle = handle;
  658. item->type = type;
  659. uv_mutex_lock(&loop->cf_mutex);
  660. QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
  661. uv_mutex_unlock(&loop->cf_mutex);
  662. state = loop->cf_state;
  663. assert(state != NULL);
  664. pCFRunLoopSourceSignal(state->signal_source);
  665. pCFRunLoopWakeUp(state->loop);
  666. return 0;
  667. }
  668. /* Runs in UV loop to initialize handle */
  669. int uv__fsevents_init(uv_fs_event_t* handle) {
  670. int err;
  671. uv__cf_loop_state_t* state;
  672. err = uv__fsevents_loop_init(handle->loop);
  673. if (err)
  674. return err;
  675. /* Get absolute path to file */
  676. handle->realpath = realpath(handle->path, NULL);
  677. if (handle->realpath == NULL)
  678. return UV__ERR(errno);
  679. handle->realpath_len = strlen(handle->realpath);
  680. /* Initialize event queue */
  681. QUEUE_INIT(&handle->cf_events);
  682. handle->cf_error = 0;
  683. /*
  684. * Events will occur in other thread.
  685. * Initialize callback for getting them back into event loop's thread
  686. */
  687. handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
  688. if (handle->cf_cb == NULL) {
  689. err = UV_ENOMEM;
  690. goto fail_cf_cb_malloc;
  691. }
  692. handle->cf_cb->data = handle;
  693. uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
  694. handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
  695. uv_unref((uv_handle_t*) handle->cf_cb);
  696. err = uv_mutex_init(&handle->cf_mutex);
  697. if (err)
  698. goto fail_cf_mutex_init;
  699. /* Insert handle into the list */
  700. state = handle->loop->cf_state;
  701. uv_mutex_lock(&state->fsevent_mutex);
  702. QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
  703. state->fsevent_handle_count++;
  704. state->fsevent_need_reschedule = 1;
  705. uv_mutex_unlock(&state->fsevent_mutex);
  706. /* Reschedule FSEventStream */
  707. assert(handle != NULL);
  708. err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
  709. if (err)
  710. goto fail_loop_signal;
  711. return 0;
  712. fail_loop_signal:
  713. uv_mutex_destroy(&handle->cf_mutex);
  714. fail_cf_mutex_init:
  715. uv__free(handle->cf_cb);
  716. handle->cf_cb = NULL;
  717. fail_cf_cb_malloc:
  718. uv__free(handle->realpath);
  719. handle->realpath = NULL;
  720. handle->realpath_len = 0;
  721. return err;
  722. }
  723. /* Runs in UV loop to de-initialize handle */
  724. int uv__fsevents_close(uv_fs_event_t* handle) {
  725. int err;
  726. uv__cf_loop_state_t* state;
  727. if (handle->cf_cb == NULL)
  728. return UV_EINVAL;
  729. /* Remove handle from the list */
  730. state = handle->loop->cf_state;
  731. uv_mutex_lock(&state->fsevent_mutex);
  732. QUEUE_REMOVE(&handle->cf_member);
  733. state->fsevent_handle_count--;
  734. state->fsevent_need_reschedule = 1;
  735. uv_mutex_unlock(&state->fsevent_mutex);
  736. /* Reschedule FSEventStream */
  737. assert(handle != NULL);
  738. err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
  739. if (err)
  740. return UV__ERR(err);
  741. /* Wait for deinitialization */
  742. uv_sem_wait(&state->fsevent_sem);
  743. uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
  744. handle->cf_cb = NULL;
  745. /* Free data in queue */
  746. UV__FSEVENTS_PROCESS(handle, {
  747. /* NOP */
  748. });
  749. uv_mutex_destroy(&handle->cf_mutex);
  750. uv__free(handle->realpath);
  751. handle->realpath = NULL;
  752. handle->realpath_len = 0;
  753. return 0;
  754. }
  755. #endif /* TARGET_OS_IPHONE */