예제 #1
0
static void InstallHandleSIGTERMFromRunLoop(void)
    // This routine installs HandleSIGTERMFromRunLoop as a SIGTERM handler. 
    // The wrinkle is, HandleSIGTERMFromRunLoop is called from the runloop rather 
    // than as a signal handler.  This means that HandleSIGTERMFromRunLoop is not 
    // limited to calling just the miniscule set of system calls that are safe 
    // from a signal handler.
    // 
    // This routine leaks lots of stuff.  You're only expected to call it once, 
    // from the main thread of your program.
{
    static const CFFileDescriptorContext    kContext = { 0, NULL, NULL, NULL, NULL };
    sig_t                   sigErr;
    int                     kq;
    CFFileDescriptorRef     kqRef;
    CFRunLoopSourceRef      kqSource;
    struct kevent           changes;
    int                     changeCount;
    
    // Ignore SIGTERM.  Even though we've ignored the signal, the kqueue will 
    // still see it.
    
    sigErr = signal(SIGTERM, SIG_IGN);
    assert(sigErr != SIG_ERR);
    
    // Create a kqueue and configure it to listen for the SIGTERM signal.
    
    kq = kqueue();
    assert(kq >= 0);
    
    // Use the new-in-10.5 EV_RECEIPT flag to ensure that we get what we expect.
    
    EV_SET(&changes, SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, 0, 0, NULL);
    changeCount = kevent(kq, &changes, 1, &changes, 1, NULL);
    assert(changeCount == 1);           // check that we get an event back
    assert(changes.flags & EV_ERROR);   // and that it contains error information
    assert(changes.data == 0);          // with no error
    
    // Wrap the kqueue in a CFFileDescriptor (new in Mac OS X 10.5!).  Then 
    // create a run-loop source from the CFFileDescriptor and add that to the 
    // runloop.
    
    kqRef = CFFileDescriptorCreate(NULL, kq, true, HandleSIGTERMFromRunLoop, &kContext);
    assert(kqRef != NULL);
    
    kqSource = CFFileDescriptorCreateRunLoopSource(NULL, kqRef, 0);
    assert(kqSource != NULL);
    
    CFRunLoopAddSource(CFRunLoopGetCurrent(), kqSource, kCFRunLoopDefaultMode);
    
    CFFileDescriptorEnableCallBacks(kqRef, kCFFileDescriptorReadCallBack);

    // Clean up.  We can release kqSource and kqRef because they're all being 
    // kept live by the fact that the kqSource is added to the runloop.  We 
    // must not close kq because file descriptors are not reference counted 
    // and kqRef now 'owns' this descriptor.
    
    CFRelease(kqSource);
    CFRelease(kqRef);
}
예제 #2
0
static int add_command_pipe (SeafWTMonitorPriv *priv)
{
    CFFileDescriptorContext ctx = {0, priv, NULL, NULL, NULL};
    CFFileDescriptorRef fdref = CFFileDescriptorCreate(NULL,
                                                       priv->cmd_pipe[0], true,
                                                       command_read_cb, &ctx);
    if (fdref == NULL) {
        return -1;
    }

    CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
    CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
    CFRunLoopAddSource (CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
    CFRelease(source);
    return 0;
}
예제 #3
0
static void constructCFFD(_CFFileStreamContext *fileStream, Boolean forRead, struct _CFStream *stream) {
    CFFileDescriptorContext context = {0, stream, NULL, NULL, (void *)CFCopyDescription};
    CFFileDescriptorRef cffd = CFFileDescriptorCreate(CFGetAllocator(stream), fileStream->fd, false, fileCallBack, &context);
    CFFileDescriptorEnableCallBacks(cffd, forRead ? kCFFileDescriptorReadCallBack : kCFFileDescriptorWriteCallBack);
    if (fileStream->rlInfo.rlArray) {
        CFIndex i, c = CFArrayGetCount(fileStream->rlInfo.rlArray);
        CFRunLoopSourceRef src = CFFileDescriptorCreateRunLoopSource(CFGetAllocator(stream), cffd, 0);
        for (i = 0; i+1 < c; i += 2) {
            CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(fileStream->rlInfo.rlArray, i);
            CFStringRef mode = CFArrayGetValueAtIndex(fileStream->rlInfo.rlArray, i+1);
            CFRunLoopAddSource(rl, src, mode);
        }
        CFRelease(fileStream->rlInfo.rlArray);
        CFRelease(src);
    }    
    fileStream->rlInfo.cffd = cffd;
}
예제 #4
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);
}
예제 #5
0
wxEventLoopSource *
wxCFEventLoop::AddSourceForFD(int fd,
                              wxEventLoopSourceHandler *handler,
                              int flags)
{
    wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" );

    wxScopedPtr<wxCFEventLoopSource>
        source(new wxCFEventLoopSource(handler, flags));

    CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL };
    wxCFRef<CFFileDescriptorRef>
        cffd(CFFileDescriptorCreate
             (
                  kCFAllocatorDefault,
                  fd,
                  true,   // close on invalidate
                  wx_cffiledescriptor_callback,
                  &ctx
             ));
    if ( !cffd )
        return NULL;

    wxCFRef<CFRunLoopSourceRef>
        cfsrc(CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, cffd, 0));
    if ( !cfsrc )
        return NULL;

    CFRunLoopRef cfloop = CFGetCurrentRunLoop();
    CFRunLoopAddSource(cfloop, cfsrc, kCFRunLoopDefaultMode);

    // Enable the callbacks initially.
    EnableDescriptorCallBacks(cffd, source->GetFlags());

    source->SetFileDescriptor(cffd.release());

    return source.release();
}
예제 #6
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;
}
예제 #7
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");
}
예제 #8
0
파일: fsevents.c 프로젝트: kwlzn/watchman
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;
}