11cb0ef41Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
21cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
31cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to
41cb0ef41Sopenharmony_ci * deal in the Software without restriction, including without limitation the
51cb0ef41Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
61cb0ef41Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
71cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
81cb0ef41Sopenharmony_ci *
91cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
101cb0ef41Sopenharmony_ci * all copies or substantial portions of the Software.
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
131cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
141cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
151cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
161cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
171cb0ef41Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
181cb0ef41Sopenharmony_ci * IN THE SOFTWARE.
191cb0ef41Sopenharmony_ci */
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci#include "uv.h"
221cb0ef41Sopenharmony_ci#include "internal.h"
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci#include <assert.h>
251cb0ef41Sopenharmony_ci#include <stdlib.h>
261cb0ef41Sopenharmony_ci#include <string.h>
271cb0ef41Sopenharmony_ci#include <errno.h>
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci#include <sys/sysctl.h>
301cb0ef41Sopenharmony_ci#include <sys/types.h>
311cb0ef41Sopenharmony_ci#include <sys/event.h>
321cb0ef41Sopenharmony_ci#include <sys/time.h>
331cb0ef41Sopenharmony_ci#include <unistd.h>
341cb0ef41Sopenharmony_ci#include <fcntl.h>
351cb0ef41Sopenharmony_ci#include <time.h>
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci/*
381cb0ef41Sopenharmony_ci * Required on
391cb0ef41Sopenharmony_ci * - Until at least FreeBSD 11.0
401cb0ef41Sopenharmony_ci * - Older versions of Mac OS X
411cb0ef41Sopenharmony_ci *
421cb0ef41Sopenharmony_ci * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
431cb0ef41Sopenharmony_ci */
441cb0ef41Sopenharmony_ci#ifndef EV_OOBAND
451cb0ef41Sopenharmony_ci#define EV_OOBAND  EV_FLAG1
461cb0ef41Sopenharmony_ci#endif
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cistatic void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ciint uv__kqueue_init(uv_loop_t* loop) {
521cb0ef41Sopenharmony_ci  loop->backend_fd = kqueue();
531cb0ef41Sopenharmony_ci  if (loop->backend_fd == -1)
541cb0ef41Sopenharmony_ci    return UV__ERR(errno);
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  uv__cloexec(loop->backend_fd, 1);
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  return 0;
591cb0ef41Sopenharmony_ci}
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
631cb0ef41Sopenharmony_cistatic int uv__has_forked_with_cfrunloop;
641cb0ef41Sopenharmony_ci#endif
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciint uv__io_fork(uv_loop_t* loop) {
671cb0ef41Sopenharmony_ci  int err;
681cb0ef41Sopenharmony_ci  loop->backend_fd = -1;
691cb0ef41Sopenharmony_ci  err = uv__kqueue_init(loop);
701cb0ef41Sopenharmony_ci  if (err)
711cb0ef41Sopenharmony_ci    return err;
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
741cb0ef41Sopenharmony_ci  if (loop->cf_state != NULL) {
751cb0ef41Sopenharmony_ci    /* We cannot start another CFRunloop and/or thread in the child
761cb0ef41Sopenharmony_ci       process; CF aborts if you try or if you try to touch the thread
771cb0ef41Sopenharmony_ci       at all to kill it. So the best we can do is ignore it from now
781cb0ef41Sopenharmony_ci       on. This means we can't watch directories in the same way
791cb0ef41Sopenharmony_ci       anymore (like other BSDs). It also means we cannot properly
801cb0ef41Sopenharmony_ci       clean up the allocated resources; calling
811cb0ef41Sopenharmony_ci       uv__fsevents_loop_delete from uv_loop_close will crash the
821cb0ef41Sopenharmony_ci       process. So we sidestep the issue by pretending like we never
831cb0ef41Sopenharmony_ci       started it in the first place.
841cb0ef41Sopenharmony_ci    */
851cb0ef41Sopenharmony_ci    uv__store_relaxed(&uv__has_forked_with_cfrunloop, 1);
861cb0ef41Sopenharmony_ci    uv__free(loop->cf_state);
871cb0ef41Sopenharmony_ci    loop->cf_state = NULL;
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
901cb0ef41Sopenharmony_ci  return err;
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ciint uv__io_check_fd(uv_loop_t* loop, int fd) {
951cb0ef41Sopenharmony_ci  struct kevent ev;
961cb0ef41Sopenharmony_ci  int rc;
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  rc = 0;
991cb0ef41Sopenharmony_ci  EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
1001cb0ef41Sopenharmony_ci  if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
1011cb0ef41Sopenharmony_ci    rc = UV__ERR(errno);
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
1041cb0ef41Sopenharmony_ci  if (rc == 0)
1051cb0ef41Sopenharmony_ci    if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
1061cb0ef41Sopenharmony_ci      abort();
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  return rc;
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_civoid uv__io_poll(uv_loop_t* loop, int timeout) {
1131cb0ef41Sopenharmony_ci  struct kevent events[1024];
1141cb0ef41Sopenharmony_ci  struct kevent* ev;
1151cb0ef41Sopenharmony_ci  struct timespec spec;
1161cb0ef41Sopenharmony_ci  unsigned int nevents;
1171cb0ef41Sopenharmony_ci  unsigned int revents;
1181cb0ef41Sopenharmony_ci  QUEUE* q;
1191cb0ef41Sopenharmony_ci  uv__io_t* w;
1201cb0ef41Sopenharmony_ci  uv_process_t* process;
1211cb0ef41Sopenharmony_ci  sigset_t* pset;
1221cb0ef41Sopenharmony_ci  sigset_t set;
1231cb0ef41Sopenharmony_ci  uint64_t base;
1241cb0ef41Sopenharmony_ci  uint64_t diff;
1251cb0ef41Sopenharmony_ci  int have_signals;
1261cb0ef41Sopenharmony_ci  int filter;
1271cb0ef41Sopenharmony_ci  int fflags;
1281cb0ef41Sopenharmony_ci  int count;
1291cb0ef41Sopenharmony_ci  int nfds;
1301cb0ef41Sopenharmony_ci  int fd;
1311cb0ef41Sopenharmony_ci  int op;
1321cb0ef41Sopenharmony_ci  int i;
1331cb0ef41Sopenharmony_ci  int user_timeout;
1341cb0ef41Sopenharmony_ci  int reset_timeout;
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  if (loop->nfds == 0) {
1371cb0ef41Sopenharmony_ci    assert(QUEUE_EMPTY(&loop->watcher_queue));
1381cb0ef41Sopenharmony_ci    return;
1391cb0ef41Sopenharmony_ci  }
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  nevents = 0;
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci  while (!QUEUE_EMPTY(&loop->watcher_queue)) {
1441cb0ef41Sopenharmony_ci    q = QUEUE_HEAD(&loop->watcher_queue);
1451cb0ef41Sopenharmony_ci    QUEUE_REMOVE(q);
1461cb0ef41Sopenharmony_ci    QUEUE_INIT(q);
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci    w = QUEUE_DATA(q, uv__io_t, watcher_queue);
1491cb0ef41Sopenharmony_ci    assert(w->pevents != 0);
1501cb0ef41Sopenharmony_ci    assert(w->fd >= 0);
1511cb0ef41Sopenharmony_ci    assert(w->fd < (int) loop->nwatchers);
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci    if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
1541cb0ef41Sopenharmony_ci      filter = EVFILT_READ;
1551cb0ef41Sopenharmony_ci      fflags = 0;
1561cb0ef41Sopenharmony_ci      op = EV_ADD;
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci      if (w->cb == uv__fs_event) {
1591cb0ef41Sopenharmony_ci        filter = EVFILT_VNODE;
1601cb0ef41Sopenharmony_ci        fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
1611cb0ef41Sopenharmony_ci               | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
1621cb0ef41Sopenharmony_ci        op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
1631cb0ef41Sopenharmony_ci      }
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci      EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci      if (++nevents == ARRAY_SIZE(events)) {
1681cb0ef41Sopenharmony_ci        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
1691cb0ef41Sopenharmony_ci          abort();
1701cb0ef41Sopenharmony_ci        nevents = 0;
1711cb0ef41Sopenharmony_ci      }
1721cb0ef41Sopenharmony_ci    }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci    if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
1751cb0ef41Sopenharmony_ci      EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci      if (++nevents == ARRAY_SIZE(events)) {
1781cb0ef41Sopenharmony_ci        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
1791cb0ef41Sopenharmony_ci          abort();
1801cb0ef41Sopenharmony_ci        nevents = 0;
1811cb0ef41Sopenharmony_ci      }
1821cb0ef41Sopenharmony_ci    }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci   if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
1851cb0ef41Sopenharmony_ci      EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci      if (++nevents == ARRAY_SIZE(events)) {
1881cb0ef41Sopenharmony_ci        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
1891cb0ef41Sopenharmony_ci          abort();
1901cb0ef41Sopenharmony_ci        nevents = 0;
1911cb0ef41Sopenharmony_ci      }
1921cb0ef41Sopenharmony_ci    }
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci    w->events = w->pevents;
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  pset = NULL;
1981cb0ef41Sopenharmony_ci  if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
1991cb0ef41Sopenharmony_ci    pset = &set;
2001cb0ef41Sopenharmony_ci    sigemptyset(pset);
2011cb0ef41Sopenharmony_ci    sigaddset(pset, SIGPROF);
2021cb0ef41Sopenharmony_ci  }
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci  assert(timeout >= -1);
2051cb0ef41Sopenharmony_ci  base = loop->time;
2061cb0ef41Sopenharmony_ci  count = 48; /* Benchmarks suggest this gives the best throughput. */
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
2091cb0ef41Sopenharmony_ci    reset_timeout = 1;
2101cb0ef41Sopenharmony_ci    user_timeout = timeout;
2111cb0ef41Sopenharmony_ci    timeout = 0;
2121cb0ef41Sopenharmony_ci  } else {
2131cb0ef41Sopenharmony_ci    reset_timeout = 0;
2141cb0ef41Sopenharmony_ci  }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  for (;; nevents = 0) {
2171cb0ef41Sopenharmony_ci    /* Only need to set the provider_entry_time if timeout != 0. The function
2181cb0ef41Sopenharmony_ci     * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
2191cb0ef41Sopenharmony_ci     */
2201cb0ef41Sopenharmony_ci    if (timeout != 0)
2211cb0ef41Sopenharmony_ci      uv__metrics_set_provider_entry_time(loop);
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci    if (timeout != -1) {
2241cb0ef41Sopenharmony_ci      spec.tv_sec = timeout / 1000;
2251cb0ef41Sopenharmony_ci      spec.tv_nsec = (timeout % 1000) * 1000000;
2261cb0ef41Sopenharmony_ci    }
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_ci    if (pset != NULL)
2291cb0ef41Sopenharmony_ci      pthread_sigmask(SIG_BLOCK, pset, NULL);
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci    nfds = kevent(loop->backend_fd,
2321cb0ef41Sopenharmony_ci                  events,
2331cb0ef41Sopenharmony_ci                  nevents,
2341cb0ef41Sopenharmony_ci                  events,
2351cb0ef41Sopenharmony_ci                  ARRAY_SIZE(events),
2361cb0ef41Sopenharmony_ci                  timeout == -1 ? NULL : &spec);
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci    if (pset != NULL)
2391cb0ef41Sopenharmony_ci      pthread_sigmask(SIG_UNBLOCK, pset, NULL);
2401cb0ef41Sopenharmony_ci
2411cb0ef41Sopenharmony_ci    /* Update loop->time unconditionally. It's tempting to skip the update when
2421cb0ef41Sopenharmony_ci     * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
2431cb0ef41Sopenharmony_ci     * operating system didn't reschedule our process while in the syscall.
2441cb0ef41Sopenharmony_ci     */
2451cb0ef41Sopenharmony_ci    SAVE_ERRNO(uv__update_time(loop));
2461cb0ef41Sopenharmony_ci
2471cb0ef41Sopenharmony_ci    if (nfds == 0) {
2481cb0ef41Sopenharmony_ci      if (reset_timeout != 0) {
2491cb0ef41Sopenharmony_ci        timeout = user_timeout;
2501cb0ef41Sopenharmony_ci        reset_timeout = 0;
2511cb0ef41Sopenharmony_ci        if (timeout == -1)
2521cb0ef41Sopenharmony_ci          continue;
2531cb0ef41Sopenharmony_ci        if (timeout > 0)
2541cb0ef41Sopenharmony_ci          goto update_timeout;
2551cb0ef41Sopenharmony_ci      }
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci      assert(timeout != -1);
2581cb0ef41Sopenharmony_ci      return;
2591cb0ef41Sopenharmony_ci    }
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci    if (nfds == -1) {
2621cb0ef41Sopenharmony_ci      if (errno != EINTR)
2631cb0ef41Sopenharmony_ci        abort();
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci      if (reset_timeout != 0) {
2661cb0ef41Sopenharmony_ci        timeout = user_timeout;
2671cb0ef41Sopenharmony_ci        reset_timeout = 0;
2681cb0ef41Sopenharmony_ci      }
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci      if (timeout == 0)
2711cb0ef41Sopenharmony_ci        return;
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci      if (timeout == -1)
2741cb0ef41Sopenharmony_ci        continue;
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci      /* Interrupted by a signal. Update timeout and poll again. */
2771cb0ef41Sopenharmony_ci      goto update_timeout;
2781cb0ef41Sopenharmony_ci    }
2791cb0ef41Sopenharmony_ci
2801cb0ef41Sopenharmony_ci    have_signals = 0;
2811cb0ef41Sopenharmony_ci    nevents = 0;
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci    assert(loop->watchers != NULL);
2841cb0ef41Sopenharmony_ci    loop->watchers[loop->nwatchers] = (void*) events;
2851cb0ef41Sopenharmony_ci    loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
2861cb0ef41Sopenharmony_ci    for (i = 0; i < nfds; i++) {
2871cb0ef41Sopenharmony_ci      ev = events + i;
2881cb0ef41Sopenharmony_ci      fd = ev->ident;
2891cb0ef41Sopenharmony_ci
2901cb0ef41Sopenharmony_ci      /* Handle kevent NOTE_EXIT results */
2911cb0ef41Sopenharmony_ci      if (ev->filter == EVFILT_PROC) {
2921cb0ef41Sopenharmony_ci        QUEUE_FOREACH(q, &loop->process_handles) {
2931cb0ef41Sopenharmony_ci          process = QUEUE_DATA(q, uv_process_t, queue);
2941cb0ef41Sopenharmony_ci          if (process->pid == fd) {
2951cb0ef41Sopenharmony_ci            process->flags |= UV_HANDLE_REAP;
2961cb0ef41Sopenharmony_ci            loop->flags |= UV_LOOP_REAP_CHILDREN;
2971cb0ef41Sopenharmony_ci            break;
2981cb0ef41Sopenharmony_ci          }
2991cb0ef41Sopenharmony_ci        }
3001cb0ef41Sopenharmony_ci        nevents++;
3011cb0ef41Sopenharmony_ci        continue;
3021cb0ef41Sopenharmony_ci      }
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci      /* Skip invalidated events, see uv__platform_invalidate_fd */
3051cb0ef41Sopenharmony_ci      if (fd == -1)
3061cb0ef41Sopenharmony_ci        continue;
3071cb0ef41Sopenharmony_ci      w = loop->watchers[fd];
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci      if (w == NULL) {
3101cb0ef41Sopenharmony_ci        /* File descriptor that we've stopped watching, disarm it.
3111cb0ef41Sopenharmony_ci         * TODO: batch up. */
3121cb0ef41Sopenharmony_ci        struct kevent events[1];
3131cb0ef41Sopenharmony_ci
3141cb0ef41Sopenharmony_ci        EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
3151cb0ef41Sopenharmony_ci        if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
3161cb0ef41Sopenharmony_ci          if (errno != EBADF && errno != ENOENT)
3171cb0ef41Sopenharmony_ci            abort();
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci        continue;
3201cb0ef41Sopenharmony_ci      }
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci      if (ev->filter == EVFILT_VNODE) {
3231cb0ef41Sopenharmony_ci        assert(w->events == POLLIN);
3241cb0ef41Sopenharmony_ci        assert(w->pevents == POLLIN);
3251cb0ef41Sopenharmony_ci        uv__metrics_update_idle_time(loop);
3261cb0ef41Sopenharmony_ci        w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
3271cb0ef41Sopenharmony_ci        nevents++;
3281cb0ef41Sopenharmony_ci        continue;
3291cb0ef41Sopenharmony_ci      }
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci      revents = 0;
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci      if (ev->filter == EVFILT_READ) {
3341cb0ef41Sopenharmony_ci        if (w->pevents & POLLIN) {
3351cb0ef41Sopenharmony_ci          revents |= POLLIN;
3361cb0ef41Sopenharmony_ci          w->rcount = ev->data;
3371cb0ef41Sopenharmony_ci        } else {
3381cb0ef41Sopenharmony_ci          /* TODO batch up */
3391cb0ef41Sopenharmony_ci          struct kevent events[1];
3401cb0ef41Sopenharmony_ci          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
3411cb0ef41Sopenharmony_ci          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
3421cb0ef41Sopenharmony_ci            if (errno != ENOENT)
3431cb0ef41Sopenharmony_ci              abort();
3441cb0ef41Sopenharmony_ci        }
3451cb0ef41Sopenharmony_ci        if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
3461cb0ef41Sopenharmony_ci          revents |= UV__POLLRDHUP;
3471cb0ef41Sopenharmony_ci      }
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci      if (ev->filter == EV_OOBAND) {
3501cb0ef41Sopenharmony_ci        if (w->pevents & UV__POLLPRI) {
3511cb0ef41Sopenharmony_ci          revents |= UV__POLLPRI;
3521cb0ef41Sopenharmony_ci          w->rcount = ev->data;
3531cb0ef41Sopenharmony_ci        } else {
3541cb0ef41Sopenharmony_ci          /* TODO batch up */
3551cb0ef41Sopenharmony_ci          struct kevent events[1];
3561cb0ef41Sopenharmony_ci          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
3571cb0ef41Sopenharmony_ci          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
3581cb0ef41Sopenharmony_ci            if (errno != ENOENT)
3591cb0ef41Sopenharmony_ci              abort();
3601cb0ef41Sopenharmony_ci        }
3611cb0ef41Sopenharmony_ci      }
3621cb0ef41Sopenharmony_ci
3631cb0ef41Sopenharmony_ci      if (ev->filter == EVFILT_WRITE) {
3641cb0ef41Sopenharmony_ci        if (w->pevents & POLLOUT) {
3651cb0ef41Sopenharmony_ci          revents |= POLLOUT;
3661cb0ef41Sopenharmony_ci          w->wcount = ev->data;
3671cb0ef41Sopenharmony_ci        } else {
3681cb0ef41Sopenharmony_ci          /* TODO batch up */
3691cb0ef41Sopenharmony_ci          struct kevent events[1];
3701cb0ef41Sopenharmony_ci          EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
3711cb0ef41Sopenharmony_ci          if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
3721cb0ef41Sopenharmony_ci            if (errno != ENOENT)
3731cb0ef41Sopenharmony_ci              abort();
3741cb0ef41Sopenharmony_ci        }
3751cb0ef41Sopenharmony_ci      }
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci      if (ev->flags & EV_ERROR)
3781cb0ef41Sopenharmony_ci        revents |= POLLERR;
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ci      if (revents == 0)
3811cb0ef41Sopenharmony_ci        continue;
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci      /* Run signal watchers last.  This also affects child process watchers
3841cb0ef41Sopenharmony_ci       * because those are implemented in terms of signal watchers.
3851cb0ef41Sopenharmony_ci       */
3861cb0ef41Sopenharmony_ci      if (w == &loop->signal_io_watcher) {
3871cb0ef41Sopenharmony_ci        have_signals = 1;
3881cb0ef41Sopenharmony_ci      } else {
3891cb0ef41Sopenharmony_ci        uv__metrics_update_idle_time(loop);
3901cb0ef41Sopenharmony_ci        w->cb(loop, w, revents);
3911cb0ef41Sopenharmony_ci      }
3921cb0ef41Sopenharmony_ci
3931cb0ef41Sopenharmony_ci      nevents++;
3941cb0ef41Sopenharmony_ci    }
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci    if (loop->flags & UV_LOOP_REAP_CHILDREN) {
3971cb0ef41Sopenharmony_ci      loop->flags &= ~UV_LOOP_REAP_CHILDREN;
3981cb0ef41Sopenharmony_ci      uv__wait_children(loop);
3991cb0ef41Sopenharmony_ci    }
4001cb0ef41Sopenharmony_ci
4011cb0ef41Sopenharmony_ci    if (reset_timeout != 0) {
4021cb0ef41Sopenharmony_ci      timeout = user_timeout;
4031cb0ef41Sopenharmony_ci      reset_timeout = 0;
4041cb0ef41Sopenharmony_ci    }
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ci    if (have_signals != 0) {
4071cb0ef41Sopenharmony_ci      uv__metrics_update_idle_time(loop);
4081cb0ef41Sopenharmony_ci      loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
4091cb0ef41Sopenharmony_ci    }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci    loop->watchers[loop->nwatchers] = NULL;
4121cb0ef41Sopenharmony_ci    loop->watchers[loop->nwatchers + 1] = NULL;
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci    if (have_signals != 0)
4151cb0ef41Sopenharmony_ci      return;  /* Event loop should cycle now so don't poll again. */
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ci    if (nevents != 0) {
4181cb0ef41Sopenharmony_ci      if (nfds == ARRAY_SIZE(events) && --count != 0) {
4191cb0ef41Sopenharmony_ci        /* Poll for more events but don't block this time. */
4201cb0ef41Sopenharmony_ci        timeout = 0;
4211cb0ef41Sopenharmony_ci        continue;
4221cb0ef41Sopenharmony_ci      }
4231cb0ef41Sopenharmony_ci      return;
4241cb0ef41Sopenharmony_ci    }
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci    if (timeout == 0)
4271cb0ef41Sopenharmony_ci      return;
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci    if (timeout == -1)
4301cb0ef41Sopenharmony_ci      continue;
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ciupdate_timeout:
4331cb0ef41Sopenharmony_ci    assert(timeout > 0);
4341cb0ef41Sopenharmony_ci
4351cb0ef41Sopenharmony_ci    diff = loop->time - base;
4361cb0ef41Sopenharmony_ci    if (diff >= (uint64_t) timeout)
4371cb0ef41Sopenharmony_ci      return;
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci    timeout -= diff;
4401cb0ef41Sopenharmony_ci  }
4411cb0ef41Sopenharmony_ci}
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_civoid uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
4451cb0ef41Sopenharmony_ci  struct kevent* events;
4461cb0ef41Sopenharmony_ci  uintptr_t i;
4471cb0ef41Sopenharmony_ci  uintptr_t nfds;
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  assert(loop->watchers != NULL);
4501cb0ef41Sopenharmony_ci  assert(fd >= 0);
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_ci  events = (struct kevent*) loop->watchers[loop->nwatchers];
4531cb0ef41Sopenharmony_ci  nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
4541cb0ef41Sopenharmony_ci  if (events == NULL)
4551cb0ef41Sopenharmony_ci    return;
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci  /* Invalidate events with same file descriptor */
4581cb0ef41Sopenharmony_ci  for (i = 0; i < nfds; i++)
4591cb0ef41Sopenharmony_ci    if ((int) events[i].ident == fd && events[i].filter != EVFILT_PROC)
4601cb0ef41Sopenharmony_ci      events[i].ident = -1;
4611cb0ef41Sopenharmony_ci}
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_cistatic void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
4651cb0ef41Sopenharmony_ci  uv_fs_event_t* handle;
4661cb0ef41Sopenharmony_ci  struct kevent ev;
4671cb0ef41Sopenharmony_ci  int events;
4681cb0ef41Sopenharmony_ci  const char* path;
4691cb0ef41Sopenharmony_ci#if defined(F_GETPATH)
4701cb0ef41Sopenharmony_ci  /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
4711cb0ef41Sopenharmony_ci  char pathbuf[MAXPATHLEN];
4721cb0ef41Sopenharmony_ci#endif
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ci  handle = container_of(w, uv_fs_event_t, event_watcher);
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
4771cb0ef41Sopenharmony_ci    events = UV_CHANGE;
4781cb0ef41Sopenharmony_ci  else
4791cb0ef41Sopenharmony_ci    events = UV_RENAME;
4801cb0ef41Sopenharmony_ci
4811cb0ef41Sopenharmony_ci  path = NULL;
4821cb0ef41Sopenharmony_ci#if defined(F_GETPATH)
4831cb0ef41Sopenharmony_ci  /* Also works when the file has been unlinked from the file system. Passing
4841cb0ef41Sopenharmony_ci   * in the path when the file has been deleted is arguably a little strange
4851cb0ef41Sopenharmony_ci   * but it's consistent with what the inotify backend does.
4861cb0ef41Sopenharmony_ci   */
4871cb0ef41Sopenharmony_ci  if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
4881cb0ef41Sopenharmony_ci    path = uv__basename_r(pathbuf);
4891cb0ef41Sopenharmony_ci#endif
4901cb0ef41Sopenharmony_ci  handle->cb(handle, path, events, 0);
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_ci  if (handle->event_watcher.fd == -1)
4931cb0ef41Sopenharmony_ci    return;
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  /* Watcher operates in one-shot mode, re-arm it. */
4961cb0ef41Sopenharmony_ci  fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
4971cb0ef41Sopenharmony_ci         | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci  EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
5001cb0ef41Sopenharmony_ci
5011cb0ef41Sopenharmony_ci  if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
5021cb0ef41Sopenharmony_ci    abort();
5031cb0ef41Sopenharmony_ci}
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_ci
5061cb0ef41Sopenharmony_ciint uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
5071cb0ef41Sopenharmony_ci  uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
5081cb0ef41Sopenharmony_ci  return 0;
5091cb0ef41Sopenharmony_ci}
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ciint uv_fs_event_start(uv_fs_event_t* handle,
5131cb0ef41Sopenharmony_ci                      uv_fs_event_cb cb,
5141cb0ef41Sopenharmony_ci                      const char* path,
5151cb0ef41Sopenharmony_ci                      unsigned int flags) {
5161cb0ef41Sopenharmony_ci  int fd;
5171cb0ef41Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
5181cb0ef41Sopenharmony_ci  struct stat statbuf;
5191cb0ef41Sopenharmony_ci#endif
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  if (uv__is_active(handle))
5221cb0ef41Sopenharmony_ci    return UV_EINVAL;
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci  handle->cb = cb;
5251cb0ef41Sopenharmony_ci  handle->path = uv__strdup(path);
5261cb0ef41Sopenharmony_ci  if (handle->path == NULL)
5271cb0ef41Sopenharmony_ci    return UV_ENOMEM;
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ci  /* TODO open asynchronously - but how do we report back errors? */
5301cb0ef41Sopenharmony_ci  fd = open(handle->path, O_RDONLY);
5311cb0ef41Sopenharmony_ci  if (fd == -1) {
5321cb0ef41Sopenharmony_ci    uv__free(handle->path);
5331cb0ef41Sopenharmony_ci    handle->path = NULL;
5341cb0ef41Sopenharmony_ci    return UV__ERR(errno);
5351cb0ef41Sopenharmony_ci  }
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
5381cb0ef41Sopenharmony_ci  /* Nullify field to perform checks later */
5391cb0ef41Sopenharmony_ci  handle->cf_cb = NULL;
5401cb0ef41Sopenharmony_ci  handle->realpath = NULL;
5411cb0ef41Sopenharmony_ci  handle->realpath_len = 0;
5421cb0ef41Sopenharmony_ci  handle->cf_flags = flags;
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci  if (fstat(fd, &statbuf))
5451cb0ef41Sopenharmony_ci    goto fallback;
5461cb0ef41Sopenharmony_ci  /* FSEvents works only with directories */
5471cb0ef41Sopenharmony_ci  if (!(statbuf.st_mode & S_IFDIR))
5481cb0ef41Sopenharmony_ci    goto fallback;
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ci  if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop)) {
5511cb0ef41Sopenharmony_ci    int r;
5521cb0ef41Sopenharmony_ci    /* The fallback fd is no longer needed */
5531cb0ef41Sopenharmony_ci    uv__close_nocheckstdio(fd);
5541cb0ef41Sopenharmony_ci    handle->event_watcher.fd = -1;
5551cb0ef41Sopenharmony_ci    r = uv__fsevents_init(handle);
5561cb0ef41Sopenharmony_ci    if (r == 0) {
5571cb0ef41Sopenharmony_ci      uv__handle_start(handle);
5581cb0ef41Sopenharmony_ci    } else {
5591cb0ef41Sopenharmony_ci      uv__free(handle->path);
5601cb0ef41Sopenharmony_ci      handle->path = NULL;
5611cb0ef41Sopenharmony_ci    }
5621cb0ef41Sopenharmony_ci    return r;
5631cb0ef41Sopenharmony_ci  }
5641cb0ef41Sopenharmony_cifallback:
5651cb0ef41Sopenharmony_ci#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
5661cb0ef41Sopenharmony_ci
5671cb0ef41Sopenharmony_ci  uv__handle_start(handle);
5681cb0ef41Sopenharmony_ci  uv__io_init(&handle->event_watcher, uv__fs_event, fd);
5691cb0ef41Sopenharmony_ci  uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
5701cb0ef41Sopenharmony_ci
5711cb0ef41Sopenharmony_ci  return 0;
5721cb0ef41Sopenharmony_ci}
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_ci
5751cb0ef41Sopenharmony_ciint uv_fs_event_stop(uv_fs_event_t* handle) {
5761cb0ef41Sopenharmony_ci  int r;
5771cb0ef41Sopenharmony_ci  r = 0;
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ci  if (!uv__is_active(handle))
5801cb0ef41Sopenharmony_ci    return 0;
5811cb0ef41Sopenharmony_ci
5821cb0ef41Sopenharmony_ci  uv__handle_stop(handle);
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
5851cb0ef41Sopenharmony_ci  if (0 == uv__load_relaxed(&uv__has_forked_with_cfrunloop))
5861cb0ef41Sopenharmony_ci    if (handle->cf_cb != NULL)
5871cb0ef41Sopenharmony_ci      r = uv__fsevents_close(handle);
5881cb0ef41Sopenharmony_ci#endif
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_ci  if (handle->event_watcher.fd != -1) {
5911cb0ef41Sopenharmony_ci    uv__io_close(handle->loop, &handle->event_watcher);
5921cb0ef41Sopenharmony_ci    uv__close(handle->event_watcher.fd);
5931cb0ef41Sopenharmony_ci    handle->event_watcher.fd = -1;
5941cb0ef41Sopenharmony_ci  }
5951cb0ef41Sopenharmony_ci
5961cb0ef41Sopenharmony_ci  uv__free(handle->path);
5971cb0ef41Sopenharmony_ci  handle->path = NULL;
5981cb0ef41Sopenharmony_ci
5991cb0ef41Sopenharmony_ci  return r;
6001cb0ef41Sopenharmony_ci}
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci
6031cb0ef41Sopenharmony_civoid uv__fs_event_close(uv_fs_event_t* handle) {
6041cb0ef41Sopenharmony_ci  uv_fs_event_stop(handle);
6051cb0ef41Sopenharmony_ci}
606