Blame src/unix/kqueue.c

Packit b5b901
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "internal.h"
Packit b5b901
Packit b5b901
#include <assert.h>
Packit b5b901
#include <stdlib.h>
Packit b5b901
#include <string.h>
Packit b5b901
#include <errno.h>
Packit b5b901
Packit b5b901
#include <sys/sysctl.h>
Packit b5b901
#include <sys/types.h>
Packit b5b901
#include <sys/event.h>
Packit b5b901
#include <sys/time.h>
Packit b5b901
#include <unistd.h>
Packit b5b901
#include <fcntl.h>
Packit b5b901
#include <time.h>
Packit b5b901
Packit b5b901
/*
Packit b5b901
 * Required on
Packit b5b901
 * - Until at least FreeBSD 11.0
Packit b5b901
 * - Older versions of Mac OS X
Packit b5b901
 *
Packit b5b901
 * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
Packit b5b901
 */
Packit b5b901
#ifndef EV_OOBAND
Packit b5b901
#define EV_OOBAND  EV_FLAG1
Packit b5b901
#endif
Packit b5b901
Packit b5b901
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
Packit b5b901
Packit b5b901
Packit b5b901
int uv__kqueue_init(uv_loop_t* loop) {
Packit b5b901
  loop->backend_fd = kqueue();
Packit b5b901
  if (loop->backend_fd == -1)
Packit b5b901
    return UV__ERR(errno);
Packit b5b901
Packit b5b901
  uv__cloexec(loop->backend_fd, 1);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit Service e08953
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
Packit b5b901
static int uv__has_forked_with_cfrunloop;
Packit b5b901
#endif
Packit b5b901
Packit b5b901
int uv__io_fork(uv_loop_t* loop) {
Packit b5b901
  int err;
Packit b5b901
  loop->backend_fd = -1;
Packit b5b901
  err = uv__kqueue_init(loop);
Packit b5b901
  if (err)
Packit b5b901
    return err;
Packit b5b901
Packit Service e08953
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
Packit b5b901
  if (loop->cf_state != NULL) {
Packit b5b901
    /* We cannot start another CFRunloop and/or thread in the child
Packit b5b901
       process; CF aborts if you try or if you try to touch the thread
Packit b5b901
       at all to kill it. So the best we can do is ignore it from now
Packit b5b901
       on. This means we can't watch directories in the same way
Packit b5b901
       anymore (like other BSDs). It also means we cannot properly
Packit b5b901
       clean up the allocated resources; calling
Packit b5b901
       uv__fsevents_loop_delete from uv_loop_close will crash the
Packit b5b901
       process. So we sidestep the issue by pretending like we never
Packit b5b901
       started it in the first place.
Packit b5b901
    */
Packit b5b901
    uv__has_forked_with_cfrunloop = 1;
Packit b5b901
    uv__free(loop->cf_state);
Packit b5b901
    loop->cf_state = NULL;
Packit b5b901
  }
Packit Service e08953
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
Packit b5b901
  return err;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv__io_check_fd(uv_loop_t* loop, int fd) {
Packit b5b901
  struct kevent ev;
Packit b5b901
  int rc;
Packit b5b901
Packit b5b901
  rc = 0;
Packit b5b901
  EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
Packit b5b901
  if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
Packit b5b901
    rc = UV__ERR(errno);
Packit b5b901
Packit b5b901
  EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
Packit b5b901
  if (rc == 0)
Packit b5b901
    if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
Packit b5b901
      abort();
Packit b5b901
Packit b5b901
  return rc;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__io_poll(uv_loop_t* loop, int timeout) {
Packit b5b901
  struct kevent events[1024];
Packit b5b901
  struct kevent* ev;
Packit b5b901
  struct timespec spec;
Packit b5b901
  unsigned int nevents;
Packit b5b901
  unsigned int revents;
Packit b5b901
  QUEUE* q;
Packit b5b901
  uv__io_t* w;
Packit b5b901
  sigset_t* pset;
Packit b5b901
  sigset_t set;
Packit b5b901
  uint64_t base;
Packit b5b901
  uint64_t diff;
Packit b5b901
  int have_signals;
Packit b5b901
  int filter;
Packit b5b901
  int fflags;
Packit b5b901
  int count;
Packit b5b901
  int nfds;
Packit b5b901
  int fd;
Packit b5b901
  int op;
Packit b5b901
  int i;
Packit b5b901
Packit b5b901
  if (loop->nfds == 0) {
Packit b5b901
    assert(QUEUE_EMPTY(&loop->watcher_queue));
Packit b5b901
    return;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  nevents = 0;
Packit b5b901
Packit b5b901
  while (!QUEUE_EMPTY(&loop->watcher_queue)) {
Packit b5b901
    q = QUEUE_HEAD(&loop->watcher_queue);
Packit b5b901
    QUEUE_REMOVE(q);
Packit b5b901
    QUEUE_INIT(q);
Packit b5b901
Packit b5b901
    w = QUEUE_DATA(q, uv__io_t, watcher_queue);
Packit b5b901
    assert(w->pevents != 0);
Packit b5b901
    assert(w->fd >= 0);
Packit b5b901
    assert(w->fd < (int) loop->nwatchers);
Packit b5b901
Packit b5b901
    if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
Packit b5b901
      filter = EVFILT_READ;
Packit b5b901
      fflags = 0;
Packit b5b901
      op = EV_ADD;
Packit b5b901
Packit b5b901
      if (w->cb == uv__fs_event) {
Packit b5b901
        filter = EVFILT_VNODE;
Packit b5b901
        fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
Packit b5b901
               | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
Packit b5b901
        op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
Packit b5b901
      }
Packit b5b901
Packit b5b901
      EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
Packit b5b901
Packit b5b901
      if (++nevents == ARRAY_SIZE(events)) {
Packit b5b901
        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
Packit b5b901
          abort();
Packit b5b901
        nevents = 0;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
Packit b5b901
      EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
Packit b5b901
Packit b5b901
      if (++nevents == ARRAY_SIZE(events)) {
Packit b5b901
        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
Packit b5b901
          abort();
Packit b5b901
        nevents = 0;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
   if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
Packit b5b901
      EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
Packit b5b901
Packit b5b901
      if (++nevents == ARRAY_SIZE(events)) {
Packit b5b901
        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
Packit b5b901
          abort();
Packit b5b901
        nevents = 0;
Packit b5b901
      }
Packit b5b901
    }
Packit b5b901
Packit b5b901
    w->events = w->pevents;
Packit b5b901
  }
Packit b5b901
Packit b5b901
  pset = NULL;
Packit b5b901
  if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
Packit b5b901
    pset = &set;
Packit b5b901
    sigemptyset(pset);
Packit b5b901
    sigaddset(pset, SIGPROF);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  assert(timeout >= -1);
Packit b5b901
  base = loop->time;
Packit b5b901
  count = 48; /* Benchmarks suggest this gives the best throughput. */
Packit b5b901
Packit b5b901
  for (;; nevents = 0) {
Packit b5b901
    if (timeout != -1) {
Packit b5b901
      spec.tv_sec = timeout / 1000;
Packit b5b901
      spec.tv_nsec = (timeout % 1000) * 1000000;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (pset != NULL)
Packit b5b901
      pthread_sigmask(SIG_BLOCK, pset, NULL);
Packit b5b901
Packit b5b901
    nfds = kevent(loop->backend_fd,
Packit b5b901
                  events,
Packit b5b901
                  nevents,
Packit b5b901
                  events,
Packit b5b901
                  ARRAY_SIZE(events),
Packit b5b901
                  timeout == -1 ? NULL : &spec);
Packit b5b901
Packit b5b901
    if (pset != NULL)
Packit b5b901
      pthread_sigmask(SIG_UNBLOCK, pset, NULL);
Packit b5b901
Packit b5b901
    /* Update loop->time unconditionally. It's tempting to skip the update when
Packit b5b901
     * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
Packit b5b901
     * operating system didn't reschedule our process while in the syscall.
Packit b5b901
     */
Packit b5b901
    SAVE_ERRNO(uv__update_time(loop));
Packit b5b901
Packit b5b901
    if (nfds == 0) {
Packit b5b901
      assert(timeout != -1);
Packit b5b901
      return;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (nfds == -1) {
Packit b5b901
      if (errno != EINTR)
Packit b5b901
        abort();
Packit b5b901
Packit b5b901
      if (timeout == 0)
Packit b5b901
        return;
Packit b5b901
Packit b5b901
      if (timeout == -1)
Packit b5b901
        continue;
Packit b5b901
Packit b5b901
      /* Interrupted by a signal. Update timeout and poll again. */
Packit b5b901
      goto update_timeout;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    have_signals = 0;
Packit b5b901
    nevents = 0;
Packit b5b901
Packit b5b901
    assert(loop->watchers != NULL);
Packit b5b901
    loop->watchers[loop->nwatchers] = (void*) events;
Packit b5b901
    loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
Packit b5b901
    for (i = 0; i < nfds; i++) {
Packit b5b901
      ev = events + i;
Packit b5b901
      fd = ev->ident;
Packit b5b901
      /* Skip invalidated events, see uv__platform_invalidate_fd */
Packit b5b901
      if (fd == -1)
Packit b5b901
        continue;
Packit b5b901
      w = loop->watchers[fd];
Packit b5b901
Packit b5b901
      if (w == NULL) {
Packit b5b901
        /* File descriptor that we've stopped watching, disarm it.
Packit b5b901
         * TODO: batch up. */
Packit b5b901
        struct kevent events[1];
Packit b5b901
Packit b5b901
        EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
Packit b5b901
        if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
Packit b5b901
          if (errno != EBADF && errno != ENOENT)
Packit b5b901
            abort();
Packit b5b901
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      if (ev->filter == EVFILT_VNODE) {
Packit b5b901
        assert(w->events == POLLIN);
Packit b5b901
        assert(w->pevents == POLLIN);
Packit b5b901
        w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
Packit b5b901
        nevents++;
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
Packit b5b901
      revents = 0;
Packit b5b901
Packit b5b901
      if (ev->filter == EVFILT_READ) {
Packit b5b901
        if (w->pevents & POLLIN) {
Packit b5b901
          revents |= POLLIN;
Packit b5b901
          w->rcount = ev->data;
Packit b5b901
        } else {
Packit b5b901
          /* TODO batch up */
Packit b5b901
          struct kevent events[1];
Packit b5b901
          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
Packit b5b901
          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
Packit b5b901
            if (errno != ENOENT)
Packit b5b901
              abort();
Packit b5b901
        }
Packit b5b901
      }
Packit b5b901
Packit b5b901
      if (ev->filter == EV_OOBAND) {
Packit b5b901
        if (w->pevents & UV__POLLPRI) {
Packit b5b901
          revents |= UV__POLLPRI;
Packit b5b901
          w->rcount = ev->data;
Packit b5b901
        } else {
Packit b5b901
          /* TODO batch up */
Packit b5b901
          struct kevent events[1];
Packit b5b901
          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
Packit b5b901
          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
Packit b5b901
            if (errno != ENOENT)
Packit b5b901
              abort();
Packit b5b901
        }
Packit b5b901
      }
Packit b5b901
Packit b5b901
      if (ev->filter == EVFILT_WRITE) {
Packit b5b901
        if (w->pevents & POLLOUT) {
Packit b5b901
          revents |= POLLOUT;
Packit b5b901
          w->wcount = ev->data;
Packit b5b901
        } else {
Packit b5b901
          /* TODO batch up */
Packit b5b901
          struct kevent events[1];
Packit b5b901
          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
Packit b5b901
          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
Packit b5b901
            if (errno != ENOENT)
Packit b5b901
              abort();
Packit b5b901
        }
Packit b5b901
      }
Packit b5b901
Packit b5b901
      if (ev->flags & EV_ERROR)
Packit b5b901
        revents |= POLLERR;
Packit b5b901
Packit b5b901
      if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
Packit b5b901
        revents |= UV__POLLRDHUP;
Packit b5b901
Packit b5b901
      if (revents == 0)
Packit b5b901
        continue;
Packit b5b901
Packit b5b901
      /* Run signal watchers last.  This also affects child process watchers
Packit b5b901
       * because those are implemented in terms of signal watchers.
Packit b5b901
       */
Packit b5b901
      if (w == &loop->signal_io_watcher)
Packit b5b901
        have_signals = 1;
Packit b5b901
      else
Packit b5b901
        w->cb(loop, w, revents);
Packit b5b901
Packit b5b901
      nevents++;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (have_signals != 0)
Packit b5b901
      loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
Packit b5b901
Packit b5b901
    loop->watchers[loop->nwatchers] = NULL;
Packit b5b901
    loop->watchers[loop->nwatchers + 1] = NULL;
Packit b5b901
Packit b5b901
    if (have_signals != 0)
Packit b5b901
      return;  /* Event loop should cycle now so don't poll again. */
Packit b5b901
Packit b5b901
    if (nevents != 0) {
Packit b5b901
      if (nfds == ARRAY_SIZE(events) && --count != 0) {
Packit b5b901
        /* Poll for more events but don't block this time. */
Packit b5b901
        timeout = 0;
Packit b5b901
        continue;
Packit b5b901
      }
Packit b5b901
      return;
Packit b5b901
    }
Packit b5b901
Packit b5b901
    if (timeout == 0)
Packit b5b901
      return;
Packit b5b901
Packit b5b901
    if (timeout == -1)
Packit b5b901
      continue;
Packit b5b901
Packit b5b901
update_timeout:
Packit b5b901
    assert(timeout > 0);
Packit b5b901
Packit b5b901
    diff = loop->time - base;
Packit b5b901
    if (diff >= (uint64_t) timeout)
Packit b5b901
      return;
Packit b5b901
Packit b5b901
    timeout -= diff;
Packit b5b901
  }
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
Packit b5b901
  struct kevent* events;
Packit b5b901
  uintptr_t i;
Packit b5b901
  uintptr_t nfds;
Packit b5b901
Packit b5b901
  assert(loop->watchers != NULL);
Packit Service e08953
  assert(fd >= 0);
Packit b5b901
Packit b5b901
  events = (struct kevent*) loop->watchers[loop->nwatchers];
Packit b5b901
  nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
Packit b5b901
  if (events == NULL)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  /* Invalidate events with same file descriptor */
Packit b5b901
  for (i = 0; i < nfds; i++)
Packit b5b901
    if ((int) events[i].ident == fd)
Packit b5b901
      events[i].ident = -1;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
Packit b5b901
  uv_fs_event_t* handle;
Packit b5b901
  struct kevent ev;
Packit b5b901
  int events;
Packit b5b901
  const char* path;
Packit b5b901
#if defined(F_GETPATH)
Packit b5b901
  /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
Packit b5b901
  char pathbuf[MAXPATHLEN];
Packit b5b901
#endif
Packit b5b901
Packit b5b901
  handle = container_of(w, uv_fs_event_t, event_watcher);
Packit b5b901
Packit b5b901
  if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
Packit b5b901
    events = UV_CHANGE;
Packit b5b901
  else
Packit b5b901
    events = UV_RENAME;
Packit b5b901
Packit b5b901
  path = NULL;
Packit b5b901
#if defined(F_GETPATH)
Packit b5b901
  /* Also works when the file has been unlinked from the file system. Passing
Packit b5b901
   * in the path when the file has been deleted is arguably a little strange
Packit b5b901
   * but it's consistent with what the inotify backend does.
Packit b5b901
   */
Packit b5b901
  if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
Packit b5b901
    path = uv__basename_r(pathbuf);
Packit b5b901
#endif
Packit b5b901
  handle->cb(handle, path, events, 0);
Packit b5b901
Packit b5b901
  if (handle->event_watcher.fd == -1)
Packit b5b901
    return;
Packit b5b901
Packit b5b901
  /* Watcher operates in one-shot mode, re-arm it. */
Packit b5b901
  fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
Packit b5b901
         | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
Packit b5b901
Packit b5b901
  EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
Packit b5b901
Packit b5b901
  if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
Packit b5b901
    abort();
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
Packit b5b901
  uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_start(uv_fs_event_t* handle,
Packit b5b901
                      uv_fs_event_cb cb,
Packit b5b901
                      const char* path,
Packit b5b901
                      unsigned int flags) {
Packit b5b901
  int fd;
Packit Service e08953
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
Packit Service e08953
  struct stat statbuf;
Packit Service e08953
#endif
Packit b5b901
Packit b5b901
  if (uv__is_active(handle))
Packit b5b901
    return UV_EINVAL;
Packit b5b901
Packit b5b901
  handle->cb = cb;
Packit Service e08953
  handle->path = uv__strdup(path);
Packit Service e08953
  if (handle->path == NULL)
Packit Service e08953
    return UV_ENOMEM;
Packit b5b901
Packit Service e08953
  /* TODO open asynchronously - but how do we report back errors? */
Packit Service e08953
  fd = open(handle->path, O_RDONLY);
Packit Service e08953
  if (fd == -1) {
Packit Service e08953
    uv__free(handle->path);
Packit Service e08953
    handle->path = NULL;
Packit Service e08953
    return UV__ERR(errno);
Packit Service e08953
  }
Packit b5b901
Packit Service e08953
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
Packit b5b901
  /* Nullify field to perform checks later */
Packit b5b901
  handle->cf_cb = NULL;
Packit b5b901
  handle->realpath = NULL;
Packit b5b901
  handle->realpath_len = 0;
Packit b5b901
  handle->cf_flags = flags;
Packit b5b901
Packit b5b901
  if (fstat(fd, &statbuf))
Packit b5b901
    goto fallback;
Packit b5b901
  /* FSEvents works only with directories */
Packit b5b901
  if (!(statbuf.st_mode & S_IFDIR))
Packit b5b901
    goto fallback;
Packit b5b901
Packit Service e08953
  if (!uv__has_forked_with_cfrunloop) {
Packit Service e08953
    int r;
Packit Service e08953
    /* The fallback fd is no longer needed */
Packit Service e08953
    uv__close_nocheckstdio(fd);
Packit Service e08953
    handle->event_watcher.fd = -1;
Packit Service e08953
    r = uv__fsevents_init(handle);
Packit Service e08953
    if (r == 0) {
Packit Service e08953
      uv__handle_start(handle);
Packit Service e08953
    } else {
Packit Service e08953
      uv__free(handle->path);
Packit Service e08953
      handle->path = NULL;
Packit Service e08953
    }
Packit Service e08953
    return r;
Packit Service e08953
  }
Packit b5b901
fallback:
Packit Service e08953
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
Packit b5b901
Packit Service e08953
  uv__handle_start(handle);
Packit Service e08953
  uv__io_init(&handle->event_watcher, uv__fs_event, fd);
Packit b5b901
  uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
Packit b5b901
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
int uv_fs_event_stop(uv_fs_event_t* handle) {
Packit Service e08953
  int r;
Packit Service e08953
  r = 0;
Packit Service e08953
Packit b5b901
  if (!uv__is_active(handle))
Packit b5b901
    return 0;
Packit b5b901
Packit b5b901
  uv__handle_stop(handle);
Packit b5b901
Packit Service e08953
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
Packit Service e08953
  if (!uv__has_forked_with_cfrunloop && handle->cf_cb != NULL)
Packit Service e08953
    r = uv__fsevents_close(handle);
Packit Service e08953
#endif
Packit b5b901
Packit b5b901
  if (handle->event_watcher.fd != -1) {
Packit Service e08953
    uv__io_close(handle->loop, &handle->event_watcher);
Packit b5b901
    uv__close(handle->event_watcher.fd);
Packit b5b901
    handle->event_watcher.fd = -1;
Packit b5b901
  }
Packit b5b901
Packit Service e08953
  uv__free(handle->path);
Packit Service e08953
  handle->path = NULL;
Packit Service e08953
Packit Service e08953
  return r;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
void uv__fs_event_close(uv_fs_event_t* handle) {
Packit b5b901
  uv_fs_event_stop(handle);
Packit b5b901
}