Exemplo n.º 1
0
/**
 * The main thread tells the run loop thread that a new command is ready by
 * writing to a pipe. This function tells the run loop to call a callback
 * whenever that fd is ready to be read
 */
static void listen_for_command_fd(struct thread_env *thread_env) {
  int fd = thread_env->read_command_fd;
  CFFileDescriptorContext fd_context = {};
  fd_context.info = thread_env;
  CFFileDescriptorRef fdref = CFFileDescriptorCreate(
    kCFAllocatorDefault,
    fd,
    true,
    command_callback,
    &fd_context
  );
  CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
  CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(
    kCFAllocatorDefault,
    fdref,
    0
  );
  CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
  CFRelease(source);
}
Exemplo n.º 2
0
FskErr FskFSDirectoryChangeNotifierNew(const char *path, UInt32 flags, FskDirectoryChangeNotifierCallbackProc callback, void *refCon, FskDirectoryChangeNotifier *dirChangeNotifier)
{
	FskErr err = kFskErrNone;
	FskFSDirectoryChangeNotifier directoryChangeNotifier;
	struct kevent eventToAdd;
	int errNum;
	CFFileDescriptorContext context = {0, NULL, NULL, NULL, NULL};
	CFRunLoopSourceRef rls;

	err = FskMemPtrNewClear(sizeof(FskFSDirectoryChangeNotifierRecord), (FskMemPtr *)(&directoryChangeNotifier));
	BAIL_IF_ERR(err);

	directoryChangeNotifier->base.dispatch.dispatch = &gFSDispatch;
	directoryChangeNotifier->callback = callback;
	directoryChangeNotifier->refCon = refCon;
	directoryChangeNotifier->path = FskStrDoCopy(path);
	directoryChangeNotifier->dirFD = -1;
	directoryChangeNotifier->kq = -1;
	directoryChangeNotifier->dirKQRef = NULL;

	directoryChangeNotifier->dirFD = open(path, O_EVTONLY);
	if (directoryChangeNotifier->dirFD < 0)
	{
		BAIL(kFskErrFileNotFound);
	}
    
	directoryChangeNotifier->kq = kqueue();
	if (directoryChangeNotifier->kq < 0)
	{
		BAIL(kFskErrOperationFailed);
	}
    
	eventToAdd.ident = directoryChangeNotifier->dirFD;
	eventToAdd.filter = EVFILT_VNODE;
	eventToAdd.flags = EV_ADD | EV_CLEAR;
	eventToAdd.fflags = NOTE_WRITE;
	eventToAdd.data = 0;
	eventToAdd.udata = NULL;

	errNum = kevent(directoryChangeNotifier->kq, &eventToAdd, 1, NULL, 0, NULL);
	if (errNum != 0)
	{
		BAIL(kFskErrOperationFailed);
	}

	context.info = directoryChangeNotifier;
	directoryChangeNotifier->dirKQRef = CFFileDescriptorCreate(NULL, directoryChangeNotifier->kq, true, KQCallback, &context);
	if (directoryChangeNotifier->dirKQRef == NULL)
	{
		BAIL(kFskErrOperationFailed);
	}

	rls = CFFileDescriptorCreateRunLoopSource(NULL, directoryChangeNotifier->dirKQRef, 0);
	if (rls == NULL)
	{
		BAIL(kFskErrOperationFailed);
	}

	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
	CFRelease(rls);
	CFFileDescriptorEnableCallBacks(directoryChangeNotifier->dirKQRef, kCFFileDescriptorReadCallBack);

bail:
	if (err)
	{
		FskFSDirectoryChangeNotifierDispose((FskDirectoryChangeNotifier)directoryChangeNotifier);
		directoryChangeNotifier = NULL;
	}

	*dirChangeNotifier = (FskDirectoryChangeNotifier)directoryChangeNotifier;
	return err;
}
Exemplo n.º 3
0
void FSEventsWatcher::FSEventsThread(const std::shared_ptr<w_root_t>& root) {
  CFFileDescriptorRef fdref;
  CFFileDescriptorContext fdctx;

  w_set_thread_name("fsevents %s", root->root_path.c_str());

  {
    // Block until fsevents_root_start is waiting for our initialization
    auto wlock = items_.wlock();

    attempt_resync_on_drop = root->config.getBool("fsevents_try_resync", true);

    memset(&fdctx, 0, sizeof(fdctx));
    fdctx.info = root.get();

    fdref = CFFileDescriptorCreate(
        nullptr, fse_pipe.read.fd(), true, fse_pipe_callback, &fdctx);
    CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
    {
      CFRunLoopSourceRef fdsrc;

      fdsrc = CFFileDescriptorCreateRunLoopSource(nullptr, fdref, 0);
      if (!fdsrc) {
        root->failure_reason = w_string_new_typed(
            "CFFileDescriptorCreateRunLoopSource failed", W_STRING_UNICODE);
        goto done;
      }
      CFRunLoopAddSource(CFRunLoopGetCurrent(), fdsrc, kCFRunLoopDefaultMode);
      CFRelease(fdsrc);
    }

    stream = fse_stream_make(
        root, kFSEventStreamEventIdSinceNow, root->failure_reason);
    if (!stream) {
      goto done;
    }

    if (!FSEventStreamStart(stream->stream)) {
      root->failure_reason = w_string::printf(
          "FSEventStreamStart failed, look at your log file %s for "
          "lines mentioning FSEvents and see %s#fsevents for more information\n",
          log_name,
          cfg_get_trouble_url());
      goto done;
    }

    // Signal to fsevents_root_start that we're done initializing
    fse_cond.notify_one();
  }

  // Process the events stream until we get signalled to quit
  CFRunLoopRun();

done:
  if (stream) {
    delete stream;
  }
  if (fdref) {
    CFRelease(fdref);
  }

  w_log(W_LOG_DBG, "fse_thread done\n");
}
Exemplo n.º 4
0
static void *fsevents_thread(void *arg)
{
  w_root_t *root = arg;
  FSEventStreamContext ctx;
  CFMutableArrayRef parray;
  CFStringRef cpath;
  FSEventStreamRef fs_stream = NULL;
  CFFileDescriptorContext fdctx;
  CFFileDescriptorRef fdref;
  struct fsevents_root_state *state = root->watch;
  double latency;

  w_set_thread_name("fsevents %.*s", root->root_path->len,
      root->root_path->buf);

  // Block until fsevents_root_start is waiting for our initialization
  pthread_mutex_lock(&state->fse_mtx);

  memset(&ctx, 0, sizeof(ctx));
  ctx.info = root;

  memset(&fdctx, 0, sizeof(fdctx));
  fdctx.info = root;

  fdref = CFFileDescriptorCreate(NULL, state->fse_pipe[0], true,
      fse_pipe_callback, &fdctx);
  CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
  {
    CFRunLoopSourceRef fdsrc;

    fdsrc = CFFileDescriptorCreateRunLoopSource(NULL, fdref, 0);
    if (!fdsrc) {
      root->failure_reason = w_string_new(
          "CFFileDescriptorCreateRunLoopSource failed");
      goto done;
    }
    CFRunLoopAddSource(CFRunLoopGetCurrent(), fdsrc, kCFRunLoopDefaultMode);
    CFRelease(fdsrc);
  }

  parray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
  if (!parray) {
    root->failure_reason = w_string_new("CFArrayCreateMutable failed");
    goto done;
  }

  cpath = CFStringCreateWithBytes(NULL, (const UInt8*)root->root_path->buf,
      root->root_path->len, kCFStringEncodingUTF8,
      false);
  if (!cpath) {
    root->failure_reason = w_string_new("CFStringCreateWithBytes failed");
    goto done;
  }

  CFArrayAppendValue(parray, cpath);
  CFRelease(cpath);

  latency = cfg_get_double(root, "fsevents_latency", 0.01),
  w_log(W_LOG_DBG,
      "FSEventStreamCreate for path %.*s with latency %f seconds\n",
      root->root_path->len,
      root->root_path->buf,
      latency);

  fs_stream = FSEventStreamCreate(NULL, fse_callback,
      &ctx, parray, kFSEventStreamEventIdSinceNow,
      latency,
      kFSEventStreamCreateFlagNoDefer|
      kFSEventStreamCreateFlagWatchRoot|
      kFSEventStreamCreateFlagFileEvents);

  if (!fs_stream) {
    root->failure_reason = w_string_new("FSEventStreamCreate failed");
    goto done;
  }

  FSEventStreamScheduleWithRunLoop(fs_stream,
      CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  if (!FSEventStreamStart(fs_stream)) {
    root->failure_reason = w_string_make_printf(
        "FSEventStreamStart failed, look at your log file %s for "
        "lines mentioning FSEvents and see "
        "https://facebook.github.io/watchman/docs/troubleshooting.html#"
        "fsevents for more information\n", log_name);
    goto done;
  }

  // Signal to fsevents_root_start that we're done initializing
  pthread_cond_signal(&state->fse_cond);
  pthread_mutex_unlock(&state->fse_mtx);

  // Process the events stream until we get signalled to quit
  CFRunLoopRun();

  // Since the goto's above hold fse_mtx, we should grab it here
  pthread_mutex_lock(&state->fse_mtx);
done:
  if (fs_stream) {
    FSEventStreamStop(fs_stream);
    FSEventStreamInvalidate(fs_stream);
    FSEventStreamRelease(fs_stream);
  }
  if (fdref) {
    CFRelease(fdref);
  }

  // Signal to fsevents_root_start that we're done initializing in
  // the failure path.  We'll also do this after we've completed
  // the run loop in the success path; it's a spurious wakeup but
  // harmless and saves us from adding and setting a control flag
  // in each of the failure `goto` statements. fsevents_root_dtor
  // will `pthread_join` us before `state` is freed.
  pthread_cond_signal(&state->fse_cond);
  pthread_mutex_unlock(&state->fse_mtx);

  w_log(W_LOG_DBG, "fse_thread done\n");
  w_root_delref(root);
  return NULL;
}