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