xref: /third_party/libuv/src/unix/kqueue.c (revision e66f31c5)
1e66f31c5Sopenharmony_ci/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2e66f31c5Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
3e66f31c5Sopenharmony_ci * of this software and associated documentation files (the "Software"), to
4e66f31c5Sopenharmony_ci * deal in the Software without restriction, including without limitation the
5e66f31c5Sopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6e66f31c5Sopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is
7e66f31c5Sopenharmony_ci * furnished to do so, subject to the following conditions:
8e66f31c5Sopenharmony_ci *
9e66f31c5Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
10e66f31c5Sopenharmony_ci * all copies or substantial portions of the Software.
11e66f31c5Sopenharmony_ci *
12e66f31c5Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13e66f31c5Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14e66f31c5Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15e66f31c5Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16e66f31c5Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17e66f31c5Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18e66f31c5Sopenharmony_ci * IN THE SOFTWARE.
19e66f31c5Sopenharmony_ci */
20e66f31c5Sopenharmony_ci
21e66f31c5Sopenharmony_ci#include "uv.h"
22e66f31c5Sopenharmony_ci#include "internal.h"
23e66f31c5Sopenharmony_ci
24e66f31c5Sopenharmony_ci#include <assert.h>
25e66f31c5Sopenharmony_ci#include <stdlib.h>
26e66f31c5Sopenharmony_ci#include <string.h>
27e66f31c5Sopenharmony_ci#include <errno.h>
28e66f31c5Sopenharmony_ci
29e66f31c5Sopenharmony_ci#include <sys/sysctl.h>
30e66f31c5Sopenharmony_ci#include <sys/types.h>
31e66f31c5Sopenharmony_ci#include <sys/event.h>
32e66f31c5Sopenharmony_ci#include <sys/time.h>
33e66f31c5Sopenharmony_ci#if defined(__FreeBSD__)
34e66f31c5Sopenharmony_ci#include <sys/user.h>
35e66f31c5Sopenharmony_ci#endif
36e66f31c5Sopenharmony_ci#include <unistd.h>
37e66f31c5Sopenharmony_ci#include <fcntl.h>
38e66f31c5Sopenharmony_ci#include <time.h>
39e66f31c5Sopenharmony_ci
40e66f31c5Sopenharmony_ci/*
41e66f31c5Sopenharmony_ci * Required on
42e66f31c5Sopenharmony_ci * - Until at least FreeBSD 11.0
43e66f31c5Sopenharmony_ci * - Older versions of Mac OS X
44e66f31c5Sopenharmony_ci *
45e66f31c5Sopenharmony_ci * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
46e66f31c5Sopenharmony_ci */
47e66f31c5Sopenharmony_ci#ifndef EV_OOBAND
48e66f31c5Sopenharmony_ci#define EV_OOBAND  EV_FLAG1
49e66f31c5Sopenharmony_ci#endif
50e66f31c5Sopenharmony_ci
51e66f31c5Sopenharmony_cistatic void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
52e66f31c5Sopenharmony_ci
53e66f31c5Sopenharmony_ci
54e66f31c5Sopenharmony_ciint uv__kqueue_init(uv_loop_t* loop) {
55e66f31c5Sopenharmony_ci  loop->backend_fd = kqueue();
56e66f31c5Sopenharmony_ci  if (loop->backend_fd == -1)
57e66f31c5Sopenharmony_ci    return UV__ERR(errno);
58e66f31c5Sopenharmony_ci
59e66f31c5Sopenharmony_ci  uv__cloexec(loop->backend_fd, 1);
60e66f31c5Sopenharmony_ci
61e66f31c5Sopenharmony_ci  return 0;
62e66f31c5Sopenharmony_ci}
63e66f31c5Sopenharmony_ci
64e66f31c5Sopenharmony_ci
65e66f31c5Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
66e66f31c5Sopenharmony_cistatic _Atomic int uv__has_forked_with_cfrunloop;
67e66f31c5Sopenharmony_ci#endif
68e66f31c5Sopenharmony_ci
69e66f31c5Sopenharmony_ciint uv__io_fork(uv_loop_t* loop) {
70e66f31c5Sopenharmony_ci  int err;
71e66f31c5Sopenharmony_ci  loop->backend_fd = -1;
72e66f31c5Sopenharmony_ci  err = uv__kqueue_init(loop);
73e66f31c5Sopenharmony_ci  if (err)
74e66f31c5Sopenharmony_ci    return err;
75e66f31c5Sopenharmony_ci
76e66f31c5Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
77e66f31c5Sopenharmony_ci  if (loop->cf_state != NULL) {
78e66f31c5Sopenharmony_ci    /* We cannot start another CFRunloop and/or thread in the child
79e66f31c5Sopenharmony_ci       process; CF aborts if you try or if you try to touch the thread
80e66f31c5Sopenharmony_ci       at all to kill it. So the best we can do is ignore it from now
81e66f31c5Sopenharmony_ci       on. This means we can't watch directories in the same way
82e66f31c5Sopenharmony_ci       anymore (like other BSDs). It also means we cannot properly
83e66f31c5Sopenharmony_ci       clean up the allocated resources; calling
84e66f31c5Sopenharmony_ci       uv__fsevents_loop_delete from uv_loop_close will crash the
85e66f31c5Sopenharmony_ci       process. So we sidestep the issue by pretending like we never
86e66f31c5Sopenharmony_ci       started it in the first place.
87e66f31c5Sopenharmony_ci    */
88e66f31c5Sopenharmony_ci    atomic_store_explicit(&uv__has_forked_with_cfrunloop,
89e66f31c5Sopenharmony_ci                          1,
90e66f31c5Sopenharmony_ci                          memory_order_relaxed);
91e66f31c5Sopenharmony_ci    uv__free(loop->cf_state);
92e66f31c5Sopenharmony_ci    loop->cf_state = NULL;
93e66f31c5Sopenharmony_ci  }
94e66f31c5Sopenharmony_ci#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
95e66f31c5Sopenharmony_ci  return err;
96e66f31c5Sopenharmony_ci}
97e66f31c5Sopenharmony_ci
98e66f31c5Sopenharmony_ci
99e66f31c5Sopenharmony_ciint uv__io_check_fd(uv_loop_t* loop, int fd) {
100e66f31c5Sopenharmony_ci  struct kevent ev;
101e66f31c5Sopenharmony_ci  int rc;
102e66f31c5Sopenharmony_ci
103e66f31c5Sopenharmony_ci  rc = 0;
104e66f31c5Sopenharmony_ci  EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
105e66f31c5Sopenharmony_ci  if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
106e66f31c5Sopenharmony_ci    rc = UV__ERR(errno);
107e66f31c5Sopenharmony_ci
108e66f31c5Sopenharmony_ci  EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
109e66f31c5Sopenharmony_ci  if (rc == 0)
110e66f31c5Sopenharmony_ci    if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
111e66f31c5Sopenharmony_ci      abort();
112e66f31c5Sopenharmony_ci
113e66f31c5Sopenharmony_ci  return rc;
114e66f31c5Sopenharmony_ci}
115e66f31c5Sopenharmony_ci
116e66f31c5Sopenharmony_ci
117e66f31c5Sopenharmony_cistatic void uv__kqueue_delete(int kqfd, const struct kevent *ev) {
118e66f31c5Sopenharmony_ci  struct kevent change;
119e66f31c5Sopenharmony_ci
120e66f31c5Sopenharmony_ci  EV_SET(&change, ev->ident, ev->filter, EV_DELETE, 0, 0, 0);
121e66f31c5Sopenharmony_ci
122e66f31c5Sopenharmony_ci  if (0 == kevent(kqfd, &change, 1, NULL, 0, NULL))
123e66f31c5Sopenharmony_ci    return;
124e66f31c5Sopenharmony_ci
125e66f31c5Sopenharmony_ci  if (errno == EBADF || errno == ENOENT)
126e66f31c5Sopenharmony_ci    return;
127e66f31c5Sopenharmony_ci
128e66f31c5Sopenharmony_ci  abort();
129e66f31c5Sopenharmony_ci}
130e66f31c5Sopenharmony_ci
131e66f31c5Sopenharmony_ci
132e66f31c5Sopenharmony_civoid uv__io_poll(uv_loop_t* loop, int timeout) {
133e66f31c5Sopenharmony_ci  uv__loop_internal_fields_t* lfields;
134e66f31c5Sopenharmony_ci  struct kevent events[1024];
135e66f31c5Sopenharmony_ci  struct kevent* ev;
136e66f31c5Sopenharmony_ci  struct timespec spec;
137e66f31c5Sopenharmony_ci  unsigned int nevents;
138e66f31c5Sopenharmony_ci  unsigned int revents;
139e66f31c5Sopenharmony_ci  struct uv__queue* q;
140e66f31c5Sopenharmony_ci  uv__io_t* w;
141e66f31c5Sopenharmony_ci  uv_process_t* process;
142e66f31c5Sopenharmony_ci  sigset_t* pset;
143e66f31c5Sopenharmony_ci  sigset_t set;
144e66f31c5Sopenharmony_ci  uint64_t base;
145e66f31c5Sopenharmony_ci  uint64_t diff;
146e66f31c5Sopenharmony_ci  int have_signals;
147e66f31c5Sopenharmony_ci  int filter;
148e66f31c5Sopenharmony_ci  int fflags;
149e66f31c5Sopenharmony_ci  int count;
150e66f31c5Sopenharmony_ci  int nfds;
151e66f31c5Sopenharmony_ci  int fd;
152e66f31c5Sopenharmony_ci  int op;
153e66f31c5Sopenharmony_ci  int i;
154e66f31c5Sopenharmony_ci  int user_timeout;
155e66f31c5Sopenharmony_ci  int reset_timeout;
156e66f31c5Sopenharmony_ci
157e66f31c5Sopenharmony_ci  if (loop->nfds == 0) {
158e66f31c5Sopenharmony_ci    assert(uv__queue_empty(&loop->watcher_queue));
159e66f31c5Sopenharmony_ci    return;
160e66f31c5Sopenharmony_ci  }
161e66f31c5Sopenharmony_ci
162e66f31c5Sopenharmony_ci  lfields = uv__get_internal_fields(loop);
163e66f31c5Sopenharmony_ci  nevents = 0;
164e66f31c5Sopenharmony_ci
165e66f31c5Sopenharmony_ci  while (!uv__queue_empty(&loop->watcher_queue)) {
166e66f31c5Sopenharmony_ci    q = uv__queue_head(&loop->watcher_queue);
167e66f31c5Sopenharmony_ci    uv__queue_remove(q);
168e66f31c5Sopenharmony_ci    uv__queue_init(q);
169e66f31c5Sopenharmony_ci
170e66f31c5Sopenharmony_ci    w = uv__queue_data(q, uv__io_t, watcher_queue);
171e66f31c5Sopenharmony_ci    assert(w->pevents != 0);
172e66f31c5Sopenharmony_ci    assert(w->fd >= 0);
173e66f31c5Sopenharmony_ci    assert(w->fd < (int) loop->nwatchers);
174e66f31c5Sopenharmony_ci
175e66f31c5Sopenharmony_ci    if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
176e66f31c5Sopenharmony_ci      filter = EVFILT_READ;
177e66f31c5Sopenharmony_ci      fflags = 0;
178e66f31c5Sopenharmony_ci      op = EV_ADD;
179e66f31c5Sopenharmony_ci
180e66f31c5Sopenharmony_ci      if (w->cb == uv__fs_event) {
181e66f31c5Sopenharmony_ci        filter = EVFILT_VNODE;
182e66f31c5Sopenharmony_ci        fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
183e66f31c5Sopenharmony_ci               | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
184e66f31c5Sopenharmony_ci        op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
185e66f31c5Sopenharmony_ci      }
186e66f31c5Sopenharmony_ci
187e66f31c5Sopenharmony_ci      EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
188e66f31c5Sopenharmony_ci
189e66f31c5Sopenharmony_ci      if (++nevents == ARRAY_SIZE(events)) {
190e66f31c5Sopenharmony_ci        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
191e66f31c5Sopenharmony_ci          abort();
192e66f31c5Sopenharmony_ci        nevents = 0;
193e66f31c5Sopenharmony_ci      }
194e66f31c5Sopenharmony_ci    }
195e66f31c5Sopenharmony_ci
196e66f31c5Sopenharmony_ci    if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
197e66f31c5Sopenharmony_ci      EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
198e66f31c5Sopenharmony_ci
199e66f31c5Sopenharmony_ci      if (++nevents == ARRAY_SIZE(events)) {
200e66f31c5Sopenharmony_ci        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
201e66f31c5Sopenharmony_ci          abort();
202e66f31c5Sopenharmony_ci        nevents = 0;
203e66f31c5Sopenharmony_ci      }
204e66f31c5Sopenharmony_ci    }
205e66f31c5Sopenharmony_ci
206e66f31c5Sopenharmony_ci   if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
207e66f31c5Sopenharmony_ci      EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
208e66f31c5Sopenharmony_ci
209e66f31c5Sopenharmony_ci      if (++nevents == ARRAY_SIZE(events)) {
210e66f31c5Sopenharmony_ci        if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
211e66f31c5Sopenharmony_ci          abort();
212e66f31c5Sopenharmony_ci        nevents = 0;
213e66f31c5Sopenharmony_ci      }
214e66f31c5Sopenharmony_ci    }
215e66f31c5Sopenharmony_ci
216e66f31c5Sopenharmony_ci    w->events = w->pevents;
217e66f31c5Sopenharmony_ci  }
218e66f31c5Sopenharmony_ci
219e66f31c5Sopenharmony_ci  pset = NULL;
220e66f31c5Sopenharmony_ci  if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
221e66f31c5Sopenharmony_ci    pset = &set;
222e66f31c5Sopenharmony_ci    sigemptyset(pset);
223e66f31c5Sopenharmony_ci    sigaddset(pset, SIGPROF);
224e66f31c5Sopenharmony_ci  }
225e66f31c5Sopenharmony_ci
226e66f31c5Sopenharmony_ci  assert(timeout >= -1);
227e66f31c5Sopenharmony_ci  base = loop->time;
228e66f31c5Sopenharmony_ci  count = 48; /* Benchmarks suggest this gives the best throughput. */
229e66f31c5Sopenharmony_ci
230e66f31c5Sopenharmony_ci  if (lfields->flags & UV_METRICS_IDLE_TIME) {
231e66f31c5Sopenharmony_ci    reset_timeout = 1;
232e66f31c5Sopenharmony_ci    user_timeout = timeout;
233e66f31c5Sopenharmony_ci    timeout = 0;
234e66f31c5Sopenharmony_ci  } else {
235e66f31c5Sopenharmony_ci    reset_timeout = 0;
236e66f31c5Sopenharmony_ci  }
237e66f31c5Sopenharmony_ci
238e66f31c5Sopenharmony_ci  for (;; nevents = 0) {
239e66f31c5Sopenharmony_ci    /* Only need to set the provider_entry_time if timeout != 0. The function
240e66f31c5Sopenharmony_ci     * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
241e66f31c5Sopenharmony_ci     */
242e66f31c5Sopenharmony_ci    if (timeout != 0)
243e66f31c5Sopenharmony_ci      uv__metrics_set_provider_entry_time(loop);
244e66f31c5Sopenharmony_ci
245e66f31c5Sopenharmony_ci    if (timeout != -1) {
246e66f31c5Sopenharmony_ci      spec.tv_sec = timeout / 1000;
247e66f31c5Sopenharmony_ci      spec.tv_nsec = (timeout % 1000) * 1000000;
248e66f31c5Sopenharmony_ci    }
249e66f31c5Sopenharmony_ci
250e66f31c5Sopenharmony_ci    if (pset != NULL)
251e66f31c5Sopenharmony_ci      pthread_sigmask(SIG_BLOCK, pset, NULL);
252e66f31c5Sopenharmony_ci
253e66f31c5Sopenharmony_ci    /* Store the current timeout in a location that's globally accessible so
254e66f31c5Sopenharmony_ci     * other locations like uv__work_done() can determine whether the queue
255e66f31c5Sopenharmony_ci     * of events in the callback were waiting when poll was called.
256e66f31c5Sopenharmony_ci     */
257e66f31c5Sopenharmony_ci    lfields->current_timeout = timeout;
258e66f31c5Sopenharmony_ci
259e66f31c5Sopenharmony_ci    nfds = kevent(loop->backend_fd,
260e66f31c5Sopenharmony_ci                  events,
261e66f31c5Sopenharmony_ci                  nevents,
262e66f31c5Sopenharmony_ci                  events,
263e66f31c5Sopenharmony_ci                  ARRAY_SIZE(events),
264e66f31c5Sopenharmony_ci                  timeout == -1 ? NULL : &spec);
265e66f31c5Sopenharmony_ci
266e66f31c5Sopenharmony_ci    if (nfds == -1)
267e66f31c5Sopenharmony_ci      assert(errno == EINTR);
268e66f31c5Sopenharmony_ci    else if (nfds == 0)
269e66f31c5Sopenharmony_ci      /* Unlimited timeout should only return with events or signal. */
270e66f31c5Sopenharmony_ci      assert(timeout != -1);
271e66f31c5Sopenharmony_ci
272e66f31c5Sopenharmony_ci    if (pset != NULL)
273e66f31c5Sopenharmony_ci      pthread_sigmask(SIG_UNBLOCK, pset, NULL);
274e66f31c5Sopenharmony_ci
275e66f31c5Sopenharmony_ci    /* Update loop->time unconditionally. It's tempting to skip the update when
276e66f31c5Sopenharmony_ci     * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
277e66f31c5Sopenharmony_ci     * operating system didn't reschedule our process while in the syscall.
278e66f31c5Sopenharmony_ci     */
279e66f31c5Sopenharmony_ci    uv__update_time(loop);
280e66f31c5Sopenharmony_ci
281e66f31c5Sopenharmony_ci    if (nfds == 0 || nfds == -1) {
282e66f31c5Sopenharmony_ci      /* If kqueue is empty or interrupted, we might still have children ready
283e66f31c5Sopenharmony_ci       * to reap immediately. */
284e66f31c5Sopenharmony_ci      if (loop->flags & UV_LOOP_REAP_CHILDREN) {
285e66f31c5Sopenharmony_ci        loop->flags &= ~UV_LOOP_REAP_CHILDREN;
286e66f31c5Sopenharmony_ci        uv__wait_children(loop);
287e66f31c5Sopenharmony_ci        assert((reset_timeout == 0 ? timeout : user_timeout) == 0);
288e66f31c5Sopenharmony_ci        return; /* Equivalent to fall-through behavior. */
289e66f31c5Sopenharmony_ci      }
290e66f31c5Sopenharmony_ci
291e66f31c5Sopenharmony_ci      if (reset_timeout != 0) {
292e66f31c5Sopenharmony_ci        timeout = user_timeout;
293e66f31c5Sopenharmony_ci        reset_timeout = 0;
294e66f31c5Sopenharmony_ci      } else if (nfds == 0) {
295e66f31c5Sopenharmony_ci        return;
296e66f31c5Sopenharmony_ci      }
297e66f31c5Sopenharmony_ci
298e66f31c5Sopenharmony_ci      /* Interrupted by a signal. Update timeout and poll again. */
299e66f31c5Sopenharmony_ci      goto update_timeout;
300e66f31c5Sopenharmony_ci    }
301e66f31c5Sopenharmony_ci
302e66f31c5Sopenharmony_ci    have_signals = 0;
303e66f31c5Sopenharmony_ci    nevents = 0;
304e66f31c5Sopenharmony_ci
305e66f31c5Sopenharmony_ci    assert(loop->watchers != NULL);
306e66f31c5Sopenharmony_ci    loop->watchers[loop->nwatchers] = (void*) events;
307e66f31c5Sopenharmony_ci    loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
308e66f31c5Sopenharmony_ci    for (i = 0; i < nfds; i++) {
309e66f31c5Sopenharmony_ci      ev = events + i;
310e66f31c5Sopenharmony_ci      fd = ev->ident;
311e66f31c5Sopenharmony_ci
312e66f31c5Sopenharmony_ci      /* Handle kevent NOTE_EXIT results */
313e66f31c5Sopenharmony_ci      if (ev->filter == EVFILT_PROC) {
314e66f31c5Sopenharmony_ci        uv__queue_foreach(q, &loop->process_handles) {
315e66f31c5Sopenharmony_ci          process = uv__queue_data(q, uv_process_t, queue);
316e66f31c5Sopenharmony_ci          if (process->pid == fd) {
317e66f31c5Sopenharmony_ci            process->flags |= UV_HANDLE_REAP;
318e66f31c5Sopenharmony_ci            loop->flags |= UV_LOOP_REAP_CHILDREN;
319e66f31c5Sopenharmony_ci            break;
320e66f31c5Sopenharmony_ci          }
321e66f31c5Sopenharmony_ci        }
322e66f31c5Sopenharmony_ci        nevents++;
323e66f31c5Sopenharmony_ci        continue;
324e66f31c5Sopenharmony_ci      }
325e66f31c5Sopenharmony_ci
326e66f31c5Sopenharmony_ci      /* Skip invalidated events, see uv__platform_invalidate_fd */
327e66f31c5Sopenharmony_ci      if (fd == -1)
328e66f31c5Sopenharmony_ci        continue;
329e66f31c5Sopenharmony_ci      w = loop->watchers[fd];
330e66f31c5Sopenharmony_ci
331e66f31c5Sopenharmony_ci      if (w == NULL) {
332e66f31c5Sopenharmony_ci        /* File descriptor that we've stopped watching, disarm it. */
333e66f31c5Sopenharmony_ci        uv__kqueue_delete(loop->backend_fd, ev);
334e66f31c5Sopenharmony_ci        continue;
335e66f31c5Sopenharmony_ci      }
336e66f31c5Sopenharmony_ci
337e66f31c5Sopenharmony_ci      if (ev->filter == EVFILT_VNODE) {
338e66f31c5Sopenharmony_ci        assert(w->events == POLLIN);
339e66f31c5Sopenharmony_ci        assert(w->pevents == POLLIN);
340e66f31c5Sopenharmony_ci        uv__metrics_update_idle_time(loop);
341e66f31c5Sopenharmony_ci        w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
342e66f31c5Sopenharmony_ci        nevents++;
343e66f31c5Sopenharmony_ci        continue;
344e66f31c5Sopenharmony_ci      }
345e66f31c5Sopenharmony_ci
346e66f31c5Sopenharmony_ci      revents = 0;
347e66f31c5Sopenharmony_ci
348e66f31c5Sopenharmony_ci      if (ev->filter == EVFILT_READ) {
349e66f31c5Sopenharmony_ci        if (w->pevents & POLLIN)
350e66f31c5Sopenharmony_ci          revents |= POLLIN;
351e66f31c5Sopenharmony_ci        else
352e66f31c5Sopenharmony_ci          uv__kqueue_delete(loop->backend_fd, ev);
353e66f31c5Sopenharmony_ci
354e66f31c5Sopenharmony_ci        if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
355e66f31c5Sopenharmony_ci          revents |= UV__POLLRDHUP;
356e66f31c5Sopenharmony_ci      }
357e66f31c5Sopenharmony_ci
358e66f31c5Sopenharmony_ci      if (ev->filter == EV_OOBAND) {
359e66f31c5Sopenharmony_ci        if (w->pevents & UV__POLLPRI)
360e66f31c5Sopenharmony_ci          revents |= UV__POLLPRI;
361e66f31c5Sopenharmony_ci        else
362e66f31c5Sopenharmony_ci          uv__kqueue_delete(loop->backend_fd, ev);
363e66f31c5Sopenharmony_ci      }
364e66f31c5Sopenharmony_ci
365e66f31c5Sopenharmony_ci      if (ev->filter == EVFILT_WRITE) {
366e66f31c5Sopenharmony_ci        if (w->pevents & POLLOUT)
367e66f31c5Sopenharmony_ci          revents |= POLLOUT;
368e66f31c5Sopenharmony_ci        else
369e66f31c5Sopenharmony_ci          uv__kqueue_delete(loop->backend_fd, ev);
370e66f31c5Sopenharmony_ci      }
371e66f31c5Sopenharmony_ci
372e66f31c5Sopenharmony_ci      if (ev->flags & EV_ERROR)
373e66f31c5Sopenharmony_ci        revents |= POLLERR;
374e66f31c5Sopenharmony_ci
375e66f31c5Sopenharmony_ci      if (revents == 0)
376e66f31c5Sopenharmony_ci        continue;
377e66f31c5Sopenharmony_ci
378e66f31c5Sopenharmony_ci      /* Run signal watchers last.  This also affects child process watchers
379e66f31c5Sopenharmony_ci       * because those are implemented in terms of signal watchers.
380e66f31c5Sopenharmony_ci       */
381e66f31c5Sopenharmony_ci      if (w == &loop->signal_io_watcher) {
382e66f31c5Sopenharmony_ci        have_signals = 1;
383e66f31c5Sopenharmony_ci      } else {
384e66f31c5Sopenharmony_ci        uv__metrics_update_idle_time(loop);
385e66f31c5Sopenharmony_ci        w->cb(loop, w, revents);
386e66f31c5Sopenharmony_ci      }
387e66f31c5Sopenharmony_ci
388e66f31c5Sopenharmony_ci      nevents++;
389e66f31c5Sopenharmony_ci    }
390e66f31c5Sopenharmony_ci
391e66f31c5Sopenharmony_ci    if (loop->flags & UV_LOOP_REAP_CHILDREN) {
392e66f31c5Sopenharmony_ci      loop->flags &= ~UV_LOOP_REAP_CHILDREN;
393e66f31c5Sopenharmony_ci      uv__wait_children(loop);
394e66f31c5Sopenharmony_ci    }
395e66f31c5Sopenharmony_ci
396e66f31c5Sopenharmony_ci    uv__metrics_inc_events(loop, nevents);
397e66f31c5Sopenharmony_ci    if (reset_timeout != 0) {
398e66f31c5Sopenharmony_ci      timeout = user_timeout;
399e66f31c5Sopenharmony_ci      reset_timeout = 0;
400e66f31c5Sopenharmony_ci      uv__metrics_inc_events_waiting(loop, nevents);
401e66f31c5Sopenharmony_ci    }
402e66f31c5Sopenharmony_ci
403e66f31c5Sopenharmony_ci    if (have_signals != 0) {
404e66f31c5Sopenharmony_ci      uv__metrics_update_idle_time(loop);
405e66f31c5Sopenharmony_ci      loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
406e66f31c5Sopenharmony_ci    }
407e66f31c5Sopenharmony_ci
408e66f31c5Sopenharmony_ci    loop->watchers[loop->nwatchers] = NULL;
409e66f31c5Sopenharmony_ci    loop->watchers[loop->nwatchers + 1] = NULL;
410e66f31c5Sopenharmony_ci
411e66f31c5Sopenharmony_ci    if (have_signals != 0)
412e66f31c5Sopenharmony_ci      return;  /* Event loop should cycle now so don't poll again. */
413e66f31c5Sopenharmony_ci
414e66f31c5Sopenharmony_ci    if (nevents != 0) {
415e66f31c5Sopenharmony_ci      if (nfds == ARRAY_SIZE(events) && --count != 0) {
416e66f31c5Sopenharmony_ci        /* Poll for more events but don't block this time. */
417e66f31c5Sopenharmony_ci        timeout = 0;
418e66f31c5Sopenharmony_ci        continue;
419e66f31c5Sopenharmony_ci      }
420e66f31c5Sopenharmony_ci      return;
421e66f31c5Sopenharmony_ci    }
422e66f31c5Sopenharmony_ci
423e66f31c5Sopenharmony_ciupdate_timeout:
424e66f31c5Sopenharmony_ci    if (timeout == 0)
425e66f31c5Sopenharmony_ci      return;
426e66f31c5Sopenharmony_ci
427e66f31c5Sopenharmony_ci    if (timeout == -1)
428e66f31c5Sopenharmony_ci      continue;
429e66f31c5Sopenharmony_ci
430e66f31c5Sopenharmony_ci    assert(timeout > 0);
431e66f31c5Sopenharmony_ci
432e66f31c5Sopenharmony_ci    diff = loop->time - base;
433e66f31c5Sopenharmony_ci    if (diff >= (uint64_t) timeout)
434e66f31c5Sopenharmony_ci      return;
435e66f31c5Sopenharmony_ci
436e66f31c5Sopenharmony_ci    timeout -= diff;
437e66f31c5Sopenharmony_ci  }
438e66f31c5Sopenharmony_ci}
439e66f31c5Sopenharmony_ci
440e66f31c5Sopenharmony_ci
441e66f31c5Sopenharmony_civoid uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
442e66f31c5Sopenharmony_ci  struct kevent* events;
443e66f31c5Sopenharmony_ci  uintptr_t i;
444e66f31c5Sopenharmony_ci  uintptr_t nfds;
445e66f31c5Sopenharmony_ci
446e66f31c5Sopenharmony_ci  assert(loop->watchers != NULL);
447e66f31c5Sopenharmony_ci  assert(fd >= 0);
448e66f31c5Sopenharmony_ci
449e66f31c5Sopenharmony_ci  events = (struct kevent*) loop->watchers[loop->nwatchers];
450e66f31c5Sopenharmony_ci  nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
451e66f31c5Sopenharmony_ci  if (events == NULL)
452e66f31c5Sopenharmony_ci    return;
453e66f31c5Sopenharmony_ci
454e66f31c5Sopenharmony_ci  /* Invalidate events with same file descriptor */
455e66f31c5Sopenharmony_ci  for (i = 0; i < nfds; i++)
456e66f31c5Sopenharmony_ci    if ((int) events[i].ident == fd && events[i].filter != EVFILT_PROC)
457e66f31c5Sopenharmony_ci      events[i].ident = -1;
458e66f31c5Sopenharmony_ci}
459e66f31c5Sopenharmony_ci
460e66f31c5Sopenharmony_ci
461e66f31c5Sopenharmony_cistatic void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
462e66f31c5Sopenharmony_ci  uv_fs_event_t* handle;
463e66f31c5Sopenharmony_ci  struct kevent ev;
464e66f31c5Sopenharmony_ci  int events;
465e66f31c5Sopenharmony_ci  const char* path;
466e66f31c5Sopenharmony_ci#if defined(F_GETPATH)
467e66f31c5Sopenharmony_ci  /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
468e66f31c5Sopenharmony_ci  char pathbuf[MAXPATHLEN];
469e66f31c5Sopenharmony_ci#endif
470e66f31c5Sopenharmony_ci
471e66f31c5Sopenharmony_ci  handle = container_of(w, uv_fs_event_t, event_watcher);
472e66f31c5Sopenharmony_ci
473e66f31c5Sopenharmony_ci  if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
474e66f31c5Sopenharmony_ci    events = UV_CHANGE;
475e66f31c5Sopenharmony_ci  else
476e66f31c5Sopenharmony_ci    events = UV_RENAME;
477e66f31c5Sopenharmony_ci
478e66f31c5Sopenharmony_ci  path = NULL;
479e66f31c5Sopenharmony_ci#if defined(F_GETPATH)
480e66f31c5Sopenharmony_ci  /* Also works when the file has been unlinked from the file system. Passing
481e66f31c5Sopenharmony_ci   * in the path when the file has been deleted is arguably a little strange
482e66f31c5Sopenharmony_ci   * but it's consistent with what the inotify backend does.
483e66f31c5Sopenharmony_ci   */
484e66f31c5Sopenharmony_ci  if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
485e66f31c5Sopenharmony_ci    path = uv__basename_r(pathbuf);
486e66f31c5Sopenharmony_ci#elif defined(F_KINFO)
487e66f31c5Sopenharmony_ci  /* We try to get the file info reference from the file descriptor.
488e66f31c5Sopenharmony_ci   * the struct's kf_structsize must be initialised beforehand
489e66f31c5Sopenharmony_ci   * whether with the KINFO_FILE_SIZE constant or this way.
490e66f31c5Sopenharmony_ci   */
491e66f31c5Sopenharmony_ci  struct stat statbuf;
492e66f31c5Sopenharmony_ci  struct kinfo_file kf;
493e66f31c5Sopenharmony_ci
494e66f31c5Sopenharmony_ci  if (handle->event_watcher.fd != -1 &&
495e66f31c5Sopenharmony_ci     (!uv__fstat(handle->event_watcher.fd, &statbuf) && !(statbuf.st_mode & S_IFDIR))) {
496e66f31c5Sopenharmony_ci     /* we are purposely not using KINFO_FILE_SIZE here
497e66f31c5Sopenharmony_ci      * as it is not available on non intl archs
498e66f31c5Sopenharmony_ci      * and here it gives 1392 too on intel.
499e66f31c5Sopenharmony_ci      * anyway, the man page also mentions we can proceed
500e66f31c5Sopenharmony_ci      * this way.
501e66f31c5Sopenharmony_ci      */
502e66f31c5Sopenharmony_ci     kf.kf_structsize = sizeof(kf);
503e66f31c5Sopenharmony_ci     if (fcntl(handle->event_watcher.fd, F_KINFO, &kf) == 0)
504e66f31c5Sopenharmony_ci       path = uv__basename_r(kf.kf_path);
505e66f31c5Sopenharmony_ci  }
506e66f31c5Sopenharmony_ci#endif
507e66f31c5Sopenharmony_ci  handle->cb(handle, path, events, 0);
508e66f31c5Sopenharmony_ci
509e66f31c5Sopenharmony_ci  if (handle->event_watcher.fd == -1)
510e66f31c5Sopenharmony_ci    return;
511e66f31c5Sopenharmony_ci
512e66f31c5Sopenharmony_ci  /* Watcher operates in one-shot mode, re-arm it. */
513e66f31c5Sopenharmony_ci  fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
514e66f31c5Sopenharmony_ci         | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
515e66f31c5Sopenharmony_ci
516e66f31c5Sopenharmony_ci  EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
517e66f31c5Sopenharmony_ci
518e66f31c5Sopenharmony_ci  if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
519e66f31c5Sopenharmony_ci    abort();
520e66f31c5Sopenharmony_ci}
521e66f31c5Sopenharmony_ci
522e66f31c5Sopenharmony_ci
523e66f31c5Sopenharmony_ciint uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
524e66f31c5Sopenharmony_ci  uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
525e66f31c5Sopenharmony_ci  return 0;
526e66f31c5Sopenharmony_ci}
527e66f31c5Sopenharmony_ci
528e66f31c5Sopenharmony_ci
529e66f31c5Sopenharmony_ciint uv_fs_event_start(uv_fs_event_t* handle,
530e66f31c5Sopenharmony_ci                      uv_fs_event_cb cb,
531e66f31c5Sopenharmony_ci                      const char* path,
532e66f31c5Sopenharmony_ci                      unsigned int flags) {
533e66f31c5Sopenharmony_ci  int fd;
534e66f31c5Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
535e66f31c5Sopenharmony_ci  struct stat statbuf;
536e66f31c5Sopenharmony_ci#endif
537e66f31c5Sopenharmony_ci
538e66f31c5Sopenharmony_ci  if (uv__is_active(handle))
539e66f31c5Sopenharmony_ci    return UV_EINVAL;
540e66f31c5Sopenharmony_ci
541e66f31c5Sopenharmony_ci  handle->cb = cb;
542e66f31c5Sopenharmony_ci  handle->path = uv__strdup(path);
543e66f31c5Sopenharmony_ci  if (handle->path == NULL)
544e66f31c5Sopenharmony_ci    return UV_ENOMEM;
545e66f31c5Sopenharmony_ci
546e66f31c5Sopenharmony_ci  /* TODO open asynchronously - but how do we report back errors? */
547e66f31c5Sopenharmony_ci  fd = open(handle->path, O_RDONLY);
548e66f31c5Sopenharmony_ci  if (fd == -1) {
549e66f31c5Sopenharmony_ci    uv__free(handle->path);
550e66f31c5Sopenharmony_ci    handle->path = NULL;
551e66f31c5Sopenharmony_ci    return UV__ERR(errno);
552e66f31c5Sopenharmony_ci  }
553e66f31c5Sopenharmony_ci
554e66f31c5Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
555e66f31c5Sopenharmony_ci  /* Nullify field to perform checks later */
556e66f31c5Sopenharmony_ci  handle->cf_cb = NULL;
557e66f31c5Sopenharmony_ci  handle->realpath = NULL;
558e66f31c5Sopenharmony_ci  handle->realpath_len = 0;
559e66f31c5Sopenharmony_ci  handle->cf_flags = flags;
560e66f31c5Sopenharmony_ci
561e66f31c5Sopenharmony_ci  if (uv__fstat(fd, &statbuf))
562e66f31c5Sopenharmony_ci    goto fallback;
563e66f31c5Sopenharmony_ci  /* FSEvents works only with directories */
564e66f31c5Sopenharmony_ci  if (!(statbuf.st_mode & S_IFDIR))
565e66f31c5Sopenharmony_ci    goto fallback;
566e66f31c5Sopenharmony_ci
567e66f31c5Sopenharmony_ci  if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
568e66f31c5Sopenharmony_ci                                memory_order_relaxed)) {
569e66f31c5Sopenharmony_ci    int r;
570e66f31c5Sopenharmony_ci    /* The fallback fd is no longer needed */
571e66f31c5Sopenharmony_ci    uv__close_nocheckstdio(fd);
572e66f31c5Sopenharmony_ci    handle->event_watcher.fd = -1;
573e66f31c5Sopenharmony_ci    r = uv__fsevents_init(handle);
574e66f31c5Sopenharmony_ci    if (r == 0) {
575e66f31c5Sopenharmony_ci      uv__handle_start(handle);
576e66f31c5Sopenharmony_ci    } else {
577e66f31c5Sopenharmony_ci      uv__free(handle->path);
578e66f31c5Sopenharmony_ci      handle->path = NULL;
579e66f31c5Sopenharmony_ci    }
580e66f31c5Sopenharmony_ci    return r;
581e66f31c5Sopenharmony_ci  }
582e66f31c5Sopenharmony_cifallback:
583e66f31c5Sopenharmony_ci#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
584e66f31c5Sopenharmony_ci
585e66f31c5Sopenharmony_ci  uv__handle_start(handle);
586e66f31c5Sopenharmony_ci  uv__io_init(&handle->event_watcher, uv__fs_event, fd);
587e66f31c5Sopenharmony_ci  uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
588e66f31c5Sopenharmony_ci
589e66f31c5Sopenharmony_ci  return 0;
590e66f31c5Sopenharmony_ci}
591e66f31c5Sopenharmony_ci
592e66f31c5Sopenharmony_ci
593e66f31c5Sopenharmony_ciint uv_fs_event_stop(uv_fs_event_t* handle) {
594e66f31c5Sopenharmony_ci  int r;
595e66f31c5Sopenharmony_ci  r = 0;
596e66f31c5Sopenharmony_ci
597e66f31c5Sopenharmony_ci  if (!uv__is_active(handle))
598e66f31c5Sopenharmony_ci    return 0;
599e66f31c5Sopenharmony_ci
600e66f31c5Sopenharmony_ci  uv__handle_stop(handle);
601e66f31c5Sopenharmony_ci
602e66f31c5Sopenharmony_ci#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
603e66f31c5Sopenharmony_ci  if (0 == atomic_load_explicit(&uv__has_forked_with_cfrunloop,
604e66f31c5Sopenharmony_ci                                memory_order_relaxed))
605e66f31c5Sopenharmony_ci    if (handle->cf_cb != NULL)
606e66f31c5Sopenharmony_ci      r = uv__fsevents_close(handle);
607e66f31c5Sopenharmony_ci#endif
608e66f31c5Sopenharmony_ci
609e66f31c5Sopenharmony_ci  if (handle->event_watcher.fd != -1) {
610e66f31c5Sopenharmony_ci    uv__io_close(handle->loop, &handle->event_watcher);
611e66f31c5Sopenharmony_ci    uv__close(handle->event_watcher.fd);
612e66f31c5Sopenharmony_ci    handle->event_watcher.fd = -1;
613e66f31c5Sopenharmony_ci  }
614e66f31c5Sopenharmony_ci
615e66f31c5Sopenharmony_ci  uv__free(handle->path);
616e66f31c5Sopenharmony_ci  handle->path = NULL;
617e66f31c5Sopenharmony_ci
618e66f31c5Sopenharmony_ci  return r;
619e66f31c5Sopenharmony_ci}
620e66f31c5Sopenharmony_ci
621e66f31c5Sopenharmony_ci
622e66f31c5Sopenharmony_civoid uv__fs_event_close(uv_fs_event_t* handle) {
623e66f31c5Sopenharmony_ci  uv_fs_event_stop(handle);
624e66f31c5Sopenharmony_ci}
625