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