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