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/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their 22e66f31c5Sopenharmony_ci * EPOLL* counterparts. We use the POLL* variants in this file because that 23e66f31c5Sopenharmony_ci * is what libuv uses elsewhere. 24e66f31c5Sopenharmony_ci */ 25e66f31c5Sopenharmony_ci 26e66f31c5Sopenharmony_ci#include "uv.h" 27e66f31c5Sopenharmony_ci#include "internal.h" 28e66f31c5Sopenharmony_ci#include "uv_log.h" 29e66f31c5Sopenharmony_ci#include <inttypes.h> 30e66f31c5Sopenharmony_ci#include <stdatomic.h> 31e66f31c5Sopenharmony_ci#include <stddef.h> /* offsetof */ 32e66f31c5Sopenharmony_ci#include <stdint.h> 33e66f31c5Sopenharmony_ci#include <stdio.h> 34e66f31c5Sopenharmony_ci#include <stdlib.h> 35e66f31c5Sopenharmony_ci#include <string.h> 36e66f31c5Sopenharmony_ci#include <assert.h> 37e66f31c5Sopenharmony_ci#include <errno.h> 38e66f31c5Sopenharmony_ci 39e66f31c5Sopenharmony_ci#include <fcntl.h> 40e66f31c5Sopenharmony_ci#include <ifaddrs.h> 41e66f31c5Sopenharmony_ci#include <net/ethernet.h> 42e66f31c5Sopenharmony_ci#include <net/if.h> 43e66f31c5Sopenharmony_ci#include <netpacket/packet.h> 44e66f31c5Sopenharmony_ci#include <sys/epoll.h> 45e66f31c5Sopenharmony_ci#include <sys/inotify.h> 46e66f31c5Sopenharmony_ci#include <sys/mman.h> 47e66f31c5Sopenharmony_ci#include <sys/param.h> 48e66f31c5Sopenharmony_ci#include <sys/prctl.h> 49e66f31c5Sopenharmony_ci#include <sys/socket.h> 50e66f31c5Sopenharmony_ci#include <sys/stat.h> 51e66f31c5Sopenharmony_ci#include <sys/syscall.h> 52e66f31c5Sopenharmony_ci#include <sys/sysinfo.h> 53e66f31c5Sopenharmony_ci#include <sys/sysmacros.h> 54e66f31c5Sopenharmony_ci#include <sys/types.h> 55e66f31c5Sopenharmony_ci#include <sys/utsname.h> 56e66f31c5Sopenharmony_ci#include <time.h> 57e66f31c5Sopenharmony_ci#include <unistd.h> 58e66f31c5Sopenharmony_ci 59e66f31c5Sopenharmony_ci#ifdef USE_FFRT 60e66f31c5Sopenharmony_ci#include "ffrt.h" 61e66f31c5Sopenharmony_ci#include "c/executor_task.h" 62e66f31c5Sopenharmony_ci 63e66f31c5Sopenharmony_ciint uv__epoll_wait(struct epoll_event* events, int eventsize, uint64_t timeout) { 64e66f31c5Sopenharmony_ci int nfds = 0; 65e66f31c5Sopenharmony_ci if (ffrt_get_cur_task() != NULL) { 66e66f31c5Sopenharmony_ci ffrt_qos_t qos = ffrt_this_task_get_qos(); 67e66f31c5Sopenharmony_ci nfds = ffrt_epoll_wait(qos, events, eventsize, timeout); 68e66f31c5Sopenharmony_ci } 69e66f31c5Sopenharmony_ci return nfds; 70e66f31c5Sopenharmony_ci} 71e66f31c5Sopenharmony_ci#endif 72e66f31c5Sopenharmony_ci 73e66f31c5Sopenharmony_ciint uv__epoll_ctl(int epoll_fd, int op, int fd, struct epoll_event* event) { 74e66f31c5Sopenharmony_ci#ifdef USE_FFRT 75e66f31c5Sopenharmony_ci if (ffrt_get_cur_task() != NULL) { 76e66f31c5Sopenharmony_ci ffrt_qos_t qos = ffrt_this_task_get_qos(); 77e66f31c5Sopenharmony_ci return ffrt_epoll_ctl(qos, op, fd, event == NULL ? 0 : event->events, NULL, NULL); 78e66f31c5Sopenharmony_ci } 79e66f31c5Sopenharmony_ci#endif 80e66f31c5Sopenharmony_ci return epoll_ctl(epoll_fd, op, fd ,event); 81e66f31c5Sopenharmony_ci} 82e66f31c5Sopenharmony_ci#ifndef __NR_io_uring_setup 83e66f31c5Sopenharmony_ci# define __NR_io_uring_setup 425 84e66f31c5Sopenharmony_ci#endif 85e66f31c5Sopenharmony_ci 86e66f31c5Sopenharmony_ci#ifndef __NR_io_uring_enter 87e66f31c5Sopenharmony_ci# define __NR_io_uring_enter 426 88e66f31c5Sopenharmony_ci#endif 89e66f31c5Sopenharmony_ci 90e66f31c5Sopenharmony_ci#ifndef __NR_io_uring_register 91e66f31c5Sopenharmony_ci# define __NR_io_uring_register 427 92e66f31c5Sopenharmony_ci#endif 93e66f31c5Sopenharmony_ci 94e66f31c5Sopenharmony_ci#ifndef __NR_copy_file_range 95e66f31c5Sopenharmony_ci# if defined(__x86_64__) 96e66f31c5Sopenharmony_ci# define __NR_copy_file_range 326 97e66f31c5Sopenharmony_ci# elif defined(__i386__) 98e66f31c5Sopenharmony_ci# define __NR_copy_file_range 377 99e66f31c5Sopenharmony_ci# elif defined(__s390__) 100e66f31c5Sopenharmony_ci# define __NR_copy_file_range 375 101e66f31c5Sopenharmony_ci# elif defined(__arm__) 102e66f31c5Sopenharmony_ci# define __NR_copy_file_range 391 103e66f31c5Sopenharmony_ci# elif defined(__aarch64__) 104e66f31c5Sopenharmony_ci# define __NR_copy_file_range 285 105e66f31c5Sopenharmony_ci# elif defined(__powerpc__) 106e66f31c5Sopenharmony_ci# define __NR_copy_file_range 379 107e66f31c5Sopenharmony_ci# elif defined(__arc__) 108e66f31c5Sopenharmony_ci# define __NR_copy_file_range 285 109e66f31c5Sopenharmony_ci# elif defined(__riscv) 110e66f31c5Sopenharmony_ci# define __NR_copy_file_range 285 111e66f31c5Sopenharmony_ci# endif 112e66f31c5Sopenharmony_ci#endif /* __NR_copy_file_range */ 113e66f31c5Sopenharmony_ci 114e66f31c5Sopenharmony_ci#ifndef __NR_statx 115e66f31c5Sopenharmony_ci# if defined(__x86_64__) 116e66f31c5Sopenharmony_ci# define __NR_statx 332 117e66f31c5Sopenharmony_ci# elif defined(__i386__) 118e66f31c5Sopenharmony_ci# define __NR_statx 383 119e66f31c5Sopenharmony_ci# elif defined(__aarch64__) 120e66f31c5Sopenharmony_ci# define __NR_statx 397 121e66f31c5Sopenharmony_ci# elif defined(__arm__) 122e66f31c5Sopenharmony_ci# define __NR_statx 397 123e66f31c5Sopenharmony_ci# elif defined(__ppc__) 124e66f31c5Sopenharmony_ci# define __NR_statx 383 125e66f31c5Sopenharmony_ci# elif defined(__s390__) 126e66f31c5Sopenharmony_ci# define __NR_statx 379 127e66f31c5Sopenharmony_ci# elif defined(__riscv) 128e66f31c5Sopenharmony_ci# define __NR_statx 291 129e66f31c5Sopenharmony_ci# endif 130e66f31c5Sopenharmony_ci#endif /* __NR_statx */ 131e66f31c5Sopenharmony_ci 132e66f31c5Sopenharmony_ci#ifndef __NR_getrandom 133e66f31c5Sopenharmony_ci# if defined(__x86_64__) 134e66f31c5Sopenharmony_ci# define __NR_getrandom 318 135e66f31c5Sopenharmony_ci# elif defined(__i386__) 136e66f31c5Sopenharmony_ci# define __NR_getrandom 355 137e66f31c5Sopenharmony_ci# elif defined(__aarch64__) 138e66f31c5Sopenharmony_ci# define __NR_getrandom 384 139e66f31c5Sopenharmony_ci# elif defined(__arm__) 140e66f31c5Sopenharmony_ci# define __NR_getrandom 384 141e66f31c5Sopenharmony_ci# elif defined(__ppc__) 142e66f31c5Sopenharmony_ci# define __NR_getrandom 359 143e66f31c5Sopenharmony_ci# elif defined(__s390__) 144e66f31c5Sopenharmony_ci# define __NR_getrandom 349 145e66f31c5Sopenharmony_ci# elif defined(__riscv) 146e66f31c5Sopenharmony_ci# define __NR_getrandom 278 147e66f31c5Sopenharmony_ci# endif 148e66f31c5Sopenharmony_ci#endif /* __NR_getrandom */ 149e66f31c5Sopenharmony_ci 150e66f31c5Sopenharmony_cienum { 151e66f31c5Sopenharmony_ci UV__IORING_SETUP_SQPOLL = 2u, 152e66f31c5Sopenharmony_ci}; 153e66f31c5Sopenharmony_ci 154e66f31c5Sopenharmony_cienum { 155e66f31c5Sopenharmony_ci UV__IORING_FEAT_SINGLE_MMAP = 1u, 156e66f31c5Sopenharmony_ci UV__IORING_FEAT_NODROP = 2u, 157e66f31c5Sopenharmony_ci UV__IORING_FEAT_RSRC_TAGS = 1024u, /* linux v5.13 */ 158e66f31c5Sopenharmony_ci}; 159e66f31c5Sopenharmony_ci 160e66f31c5Sopenharmony_cienum { 161e66f31c5Sopenharmony_ci UV__IORING_OP_READV = 1, 162e66f31c5Sopenharmony_ci UV__IORING_OP_WRITEV = 2, 163e66f31c5Sopenharmony_ci UV__IORING_OP_FSYNC = 3, 164e66f31c5Sopenharmony_ci UV__IORING_OP_OPENAT = 18, 165e66f31c5Sopenharmony_ci UV__IORING_OP_CLOSE = 19, 166e66f31c5Sopenharmony_ci UV__IORING_OP_STATX = 21, 167e66f31c5Sopenharmony_ci UV__IORING_OP_EPOLL_CTL = 29, 168e66f31c5Sopenharmony_ci UV__IORING_OP_RENAMEAT = 35, 169e66f31c5Sopenharmony_ci UV__IORING_OP_UNLINKAT = 36, 170e66f31c5Sopenharmony_ci UV__IORING_OP_MKDIRAT = 37, 171e66f31c5Sopenharmony_ci UV__IORING_OP_SYMLINKAT = 38, 172e66f31c5Sopenharmony_ci UV__IORING_OP_LINKAT = 39, 173e66f31c5Sopenharmony_ci}; 174e66f31c5Sopenharmony_ci 175e66f31c5Sopenharmony_cienum { 176e66f31c5Sopenharmony_ci UV__IORING_ENTER_GETEVENTS = 1u, 177e66f31c5Sopenharmony_ci UV__IORING_ENTER_SQ_WAKEUP = 2u, 178e66f31c5Sopenharmony_ci}; 179e66f31c5Sopenharmony_ci 180e66f31c5Sopenharmony_cienum { 181e66f31c5Sopenharmony_ci UV__IORING_SQ_NEED_WAKEUP = 1u, 182e66f31c5Sopenharmony_ci UV__IORING_SQ_CQ_OVERFLOW = 2u, 183e66f31c5Sopenharmony_ci}; 184e66f31c5Sopenharmony_ci 185e66f31c5Sopenharmony_cienum { 186e66f31c5Sopenharmony_ci UV__MKDIRAT_SYMLINKAT_LINKAT = 1u, 187e66f31c5Sopenharmony_ci}; 188e66f31c5Sopenharmony_ci 189e66f31c5Sopenharmony_cistruct uv__io_cqring_offsets { 190e66f31c5Sopenharmony_ci uint32_t head; 191e66f31c5Sopenharmony_ci uint32_t tail; 192e66f31c5Sopenharmony_ci uint32_t ring_mask; 193e66f31c5Sopenharmony_ci uint32_t ring_entries; 194e66f31c5Sopenharmony_ci uint32_t overflow; 195e66f31c5Sopenharmony_ci uint32_t cqes; 196e66f31c5Sopenharmony_ci uint64_t reserved0; 197e66f31c5Sopenharmony_ci uint64_t reserved1; 198e66f31c5Sopenharmony_ci}; 199e66f31c5Sopenharmony_ci 200e66f31c5Sopenharmony_ciSTATIC_ASSERT(40 == sizeof(struct uv__io_cqring_offsets)); 201e66f31c5Sopenharmony_ci 202e66f31c5Sopenharmony_cistruct uv__io_sqring_offsets { 203e66f31c5Sopenharmony_ci uint32_t head; 204e66f31c5Sopenharmony_ci uint32_t tail; 205e66f31c5Sopenharmony_ci uint32_t ring_mask; 206e66f31c5Sopenharmony_ci uint32_t ring_entries; 207e66f31c5Sopenharmony_ci uint32_t flags; 208e66f31c5Sopenharmony_ci uint32_t dropped; 209e66f31c5Sopenharmony_ci uint32_t array; 210e66f31c5Sopenharmony_ci uint32_t reserved0; 211e66f31c5Sopenharmony_ci uint64_t reserved1; 212e66f31c5Sopenharmony_ci}; 213e66f31c5Sopenharmony_ci 214e66f31c5Sopenharmony_ciSTATIC_ASSERT(40 == sizeof(struct uv__io_sqring_offsets)); 215e66f31c5Sopenharmony_ci 216e66f31c5Sopenharmony_cistruct uv__io_uring_cqe { 217e66f31c5Sopenharmony_ci uint64_t user_data; 218e66f31c5Sopenharmony_ci int32_t res; 219e66f31c5Sopenharmony_ci uint32_t flags; 220e66f31c5Sopenharmony_ci}; 221e66f31c5Sopenharmony_ci 222e66f31c5Sopenharmony_ciSTATIC_ASSERT(16 == sizeof(struct uv__io_uring_cqe)); 223e66f31c5Sopenharmony_ci 224e66f31c5Sopenharmony_cistruct uv__io_uring_sqe { 225e66f31c5Sopenharmony_ci uint8_t opcode; 226e66f31c5Sopenharmony_ci uint8_t flags; 227e66f31c5Sopenharmony_ci uint16_t ioprio; 228e66f31c5Sopenharmony_ci int32_t fd; 229e66f31c5Sopenharmony_ci union { 230e66f31c5Sopenharmony_ci uint64_t off; 231e66f31c5Sopenharmony_ci uint64_t addr2; 232e66f31c5Sopenharmony_ci }; 233e66f31c5Sopenharmony_ci union { 234e66f31c5Sopenharmony_ci uint64_t addr; 235e66f31c5Sopenharmony_ci }; 236e66f31c5Sopenharmony_ci uint32_t len; 237e66f31c5Sopenharmony_ci union { 238e66f31c5Sopenharmony_ci uint32_t rw_flags; 239e66f31c5Sopenharmony_ci uint32_t fsync_flags; 240e66f31c5Sopenharmony_ci uint32_t open_flags; 241e66f31c5Sopenharmony_ci uint32_t statx_flags; 242e66f31c5Sopenharmony_ci }; 243e66f31c5Sopenharmony_ci uint64_t user_data; 244e66f31c5Sopenharmony_ci union { 245e66f31c5Sopenharmony_ci uint16_t buf_index; 246e66f31c5Sopenharmony_ci uint64_t pad[3]; 247e66f31c5Sopenharmony_ci }; 248e66f31c5Sopenharmony_ci}; 249e66f31c5Sopenharmony_ci 250e66f31c5Sopenharmony_ciSTATIC_ASSERT(64 == sizeof(struct uv__io_uring_sqe)); 251e66f31c5Sopenharmony_ciSTATIC_ASSERT(0 == offsetof(struct uv__io_uring_sqe, opcode)); 252e66f31c5Sopenharmony_ciSTATIC_ASSERT(1 == offsetof(struct uv__io_uring_sqe, flags)); 253e66f31c5Sopenharmony_ciSTATIC_ASSERT(2 == offsetof(struct uv__io_uring_sqe, ioprio)); 254e66f31c5Sopenharmony_ciSTATIC_ASSERT(4 == offsetof(struct uv__io_uring_sqe, fd)); 255e66f31c5Sopenharmony_ciSTATIC_ASSERT(8 == offsetof(struct uv__io_uring_sqe, off)); 256e66f31c5Sopenharmony_ciSTATIC_ASSERT(16 == offsetof(struct uv__io_uring_sqe, addr)); 257e66f31c5Sopenharmony_ciSTATIC_ASSERT(24 == offsetof(struct uv__io_uring_sqe, len)); 258e66f31c5Sopenharmony_ciSTATIC_ASSERT(28 == offsetof(struct uv__io_uring_sqe, rw_flags)); 259e66f31c5Sopenharmony_ciSTATIC_ASSERT(32 == offsetof(struct uv__io_uring_sqe, user_data)); 260e66f31c5Sopenharmony_ciSTATIC_ASSERT(40 == offsetof(struct uv__io_uring_sqe, buf_index)); 261e66f31c5Sopenharmony_ci 262e66f31c5Sopenharmony_cistruct uv__io_uring_params { 263e66f31c5Sopenharmony_ci uint32_t sq_entries; 264e66f31c5Sopenharmony_ci uint32_t cq_entries; 265e66f31c5Sopenharmony_ci uint32_t flags; 266e66f31c5Sopenharmony_ci uint32_t sq_thread_cpu; 267e66f31c5Sopenharmony_ci uint32_t sq_thread_idle; 268e66f31c5Sopenharmony_ci uint32_t features; 269e66f31c5Sopenharmony_ci uint32_t reserved[4]; 270e66f31c5Sopenharmony_ci struct uv__io_sqring_offsets sq_off; /* 40 bytes */ 271e66f31c5Sopenharmony_ci struct uv__io_cqring_offsets cq_off; /* 40 bytes */ 272e66f31c5Sopenharmony_ci}; 273e66f31c5Sopenharmony_ci 274e66f31c5Sopenharmony_ciSTATIC_ASSERT(40 + 40 + 40 == sizeof(struct uv__io_uring_params)); 275e66f31c5Sopenharmony_ciSTATIC_ASSERT(40 == offsetof(struct uv__io_uring_params, sq_off)); 276e66f31c5Sopenharmony_ciSTATIC_ASSERT(80 == offsetof(struct uv__io_uring_params, cq_off)); 277e66f31c5Sopenharmony_ci 278e66f31c5Sopenharmony_ciSTATIC_ASSERT(EPOLL_CTL_ADD < 4); 279e66f31c5Sopenharmony_ciSTATIC_ASSERT(EPOLL_CTL_DEL < 4); 280e66f31c5Sopenharmony_ciSTATIC_ASSERT(EPOLL_CTL_MOD < 4); 281e66f31c5Sopenharmony_ci 282e66f31c5Sopenharmony_cistruct watcher_list { 283e66f31c5Sopenharmony_ci RB_ENTRY(watcher_list) entry; 284e66f31c5Sopenharmony_ci struct uv__queue watchers; 285e66f31c5Sopenharmony_ci int iterating; 286e66f31c5Sopenharmony_ci char* path; 287e66f31c5Sopenharmony_ci int wd; 288e66f31c5Sopenharmony_ci}; 289e66f31c5Sopenharmony_ci 290e66f31c5Sopenharmony_cistruct watcher_root { 291e66f31c5Sopenharmony_ci struct watcher_list* rbh_root; 292e66f31c5Sopenharmony_ci}; 293e66f31c5Sopenharmony_ci 294e66f31c5Sopenharmony_cistatic int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root); 295e66f31c5Sopenharmony_cistatic void uv__inotify_read(uv_loop_t* loop, 296e66f31c5Sopenharmony_ci uv__io_t* w, 297e66f31c5Sopenharmony_ci unsigned int revents); 298e66f31c5Sopenharmony_cistatic int compare_watchers(const struct watcher_list* a, 299e66f31c5Sopenharmony_ci const struct watcher_list* b); 300e66f31c5Sopenharmony_cistatic void maybe_free_watcher_list(struct watcher_list* w, 301e66f31c5Sopenharmony_ci uv_loop_t* loop); 302e66f31c5Sopenharmony_ci 303e66f31c5Sopenharmony_cistatic void uv__epoll_ctl_flush(int epollfd, 304e66f31c5Sopenharmony_ci struct uv__iou* ctl, 305e66f31c5Sopenharmony_ci struct epoll_event (*events)[256]); 306e66f31c5Sopenharmony_ci 307e66f31c5Sopenharmony_cistatic void uv__epoll_ctl_prep(int epollfd, 308e66f31c5Sopenharmony_ci struct uv__iou* ctl, 309e66f31c5Sopenharmony_ci struct epoll_event (*events)[256], 310e66f31c5Sopenharmony_ci int op, 311e66f31c5Sopenharmony_ci int fd, 312e66f31c5Sopenharmony_ci struct epoll_event* e); 313e66f31c5Sopenharmony_ci 314e66f31c5Sopenharmony_ciRB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers) 315e66f31c5Sopenharmony_ci 316e66f31c5Sopenharmony_ci 317e66f31c5Sopenharmony_cistatic struct watcher_root* uv__inotify_watchers(uv_loop_t* loop) { 318e66f31c5Sopenharmony_ci /* This cast works because watcher_root is a struct with a pointer as its 319e66f31c5Sopenharmony_ci * sole member. Such type punning is unsafe in the presence of strict 320e66f31c5Sopenharmony_ci * pointer aliasing (and is just plain nasty) but that is why libuv 321e66f31c5Sopenharmony_ci * is compiled with -fno-strict-aliasing. 322e66f31c5Sopenharmony_ci */ 323e66f31c5Sopenharmony_ci return (struct watcher_root*) &loop->inotify_watchers; 324e66f31c5Sopenharmony_ci} 325e66f31c5Sopenharmony_ci 326e66f31c5Sopenharmony_ci 327e66f31c5Sopenharmony_ciunsigned uv__kernel_version(void) { 328e66f31c5Sopenharmony_ci static _Atomic unsigned cached_version; 329e66f31c5Sopenharmony_ci struct utsname u; 330e66f31c5Sopenharmony_ci unsigned version; 331e66f31c5Sopenharmony_ci unsigned major; 332e66f31c5Sopenharmony_ci unsigned minor; 333e66f31c5Sopenharmony_ci unsigned patch; 334e66f31c5Sopenharmony_ci char v_sig[256]; 335e66f31c5Sopenharmony_ci char* needle; 336e66f31c5Sopenharmony_ci 337e66f31c5Sopenharmony_ci version = atomic_load_explicit(&cached_version, memory_order_relaxed); 338e66f31c5Sopenharmony_ci if (version != 0) 339e66f31c5Sopenharmony_ci return version; 340e66f31c5Sopenharmony_ci 341e66f31c5Sopenharmony_ci /* Check /proc/version_signature first as it's the way to get the mainline 342e66f31c5Sopenharmony_ci * kernel version in Ubuntu. The format is: 343e66f31c5Sopenharmony_ci * Ubuntu ubuntu_kernel_version mainline_kernel_version 344e66f31c5Sopenharmony_ci * For example: 345e66f31c5Sopenharmony_ci * Ubuntu 5.15.0-79.86-generic 5.15.111 346e66f31c5Sopenharmony_ci */ 347e66f31c5Sopenharmony_ci if (0 == uv__slurp("/proc/version_signature", v_sig, sizeof(v_sig))) 348e66f31c5Sopenharmony_ci if (3 == sscanf(v_sig, "Ubuntu %*s %u.%u.%u", &major, &minor, &patch)) 349e66f31c5Sopenharmony_ci goto calculate_version; 350e66f31c5Sopenharmony_ci 351e66f31c5Sopenharmony_ci if (-1 == uname(&u)) 352e66f31c5Sopenharmony_ci return 0; 353e66f31c5Sopenharmony_ci 354e66f31c5Sopenharmony_ci /* In Debian we need to check `version` instead of `release` to extract the 355e66f31c5Sopenharmony_ci * mainline kernel version. This is an example of how it looks like: 356e66f31c5Sopenharmony_ci * #1 SMP Debian 5.10.46-4 (2021-08-03) 357e66f31c5Sopenharmony_ci */ 358e66f31c5Sopenharmony_ci needle = strstr(u.version, "Debian "); 359e66f31c5Sopenharmony_ci if (needle != NULL) 360e66f31c5Sopenharmony_ci if (3 == sscanf(needle, "Debian %u.%u.%u", &major, &minor, &patch)) 361e66f31c5Sopenharmony_ci goto calculate_version; 362e66f31c5Sopenharmony_ci 363e66f31c5Sopenharmony_ci if (3 != sscanf(u.release, "%u.%u.%u", &major, &minor, &patch)) 364e66f31c5Sopenharmony_ci return 0; 365e66f31c5Sopenharmony_ci 366e66f31c5Sopenharmony_ci /* Handle it when the process runs under the UNAME26 personality: 367e66f31c5Sopenharmony_ci * 368e66f31c5Sopenharmony_ci * - kernels >= 3.x identify as 2.6.40+x 369e66f31c5Sopenharmony_ci * - kernels >= 4.x identify as 2.6.60+x 370e66f31c5Sopenharmony_ci * 371e66f31c5Sopenharmony_ci * UNAME26 is a poorly conceived hack that doesn't let us distinguish 372e66f31c5Sopenharmony_ci * between 4.x kernels and 5.x/6.x kernels so we conservatively assume 373e66f31c5Sopenharmony_ci * that 2.6.60+x means 4.x. 374e66f31c5Sopenharmony_ci * 375e66f31c5Sopenharmony_ci * Fun fact of the day: it's technically possible to observe the actual 376e66f31c5Sopenharmony_ci * kernel version for a brief moment because uname() first copies out the 377e66f31c5Sopenharmony_ci * real release string before overwriting it with the backcompat string. 378e66f31c5Sopenharmony_ci */ 379e66f31c5Sopenharmony_ci if (major == 2 && minor == 6) { 380e66f31c5Sopenharmony_ci if (patch >= 60) { 381e66f31c5Sopenharmony_ci major = 4; 382e66f31c5Sopenharmony_ci minor = patch - 60; 383e66f31c5Sopenharmony_ci patch = 0; 384e66f31c5Sopenharmony_ci } else if (patch >= 40) { 385e66f31c5Sopenharmony_ci major = 3; 386e66f31c5Sopenharmony_ci minor = patch - 40; 387e66f31c5Sopenharmony_ci patch = 0; 388e66f31c5Sopenharmony_ci } 389e66f31c5Sopenharmony_ci } 390e66f31c5Sopenharmony_ci 391e66f31c5Sopenharmony_cicalculate_version: 392e66f31c5Sopenharmony_ci version = major * 65536 + minor * 256 + patch; 393e66f31c5Sopenharmony_ci atomic_store_explicit(&cached_version, version, memory_order_relaxed); 394e66f31c5Sopenharmony_ci 395e66f31c5Sopenharmony_ci return version; 396e66f31c5Sopenharmony_ci} 397e66f31c5Sopenharmony_ci 398e66f31c5Sopenharmony_ci 399e66f31c5Sopenharmony_cissize_t 400e66f31c5Sopenharmony_ciuv__fs_copy_file_range(int fd_in, 401e66f31c5Sopenharmony_ci off_t* off_in, 402e66f31c5Sopenharmony_ci int fd_out, 403e66f31c5Sopenharmony_ci off_t* off_out, 404e66f31c5Sopenharmony_ci size_t len, 405e66f31c5Sopenharmony_ci unsigned int flags) 406e66f31c5Sopenharmony_ci{ 407e66f31c5Sopenharmony_ci#ifdef __NR_copy_file_range 408e66f31c5Sopenharmony_ci return syscall(__NR_copy_file_range, 409e66f31c5Sopenharmony_ci fd_in, 410e66f31c5Sopenharmony_ci off_in, 411e66f31c5Sopenharmony_ci fd_out, 412e66f31c5Sopenharmony_ci off_out, 413e66f31c5Sopenharmony_ci len, 414e66f31c5Sopenharmony_ci flags); 415e66f31c5Sopenharmony_ci#else 416e66f31c5Sopenharmony_ci return errno = ENOSYS, -1; 417e66f31c5Sopenharmony_ci#endif 418e66f31c5Sopenharmony_ci} 419e66f31c5Sopenharmony_ci 420e66f31c5Sopenharmony_ci 421e66f31c5Sopenharmony_ciint uv__statx(int dirfd, 422e66f31c5Sopenharmony_ci const char* path, 423e66f31c5Sopenharmony_ci int flags, 424e66f31c5Sopenharmony_ci unsigned int mask, 425e66f31c5Sopenharmony_ci struct uv__statx* statxbuf) { 426e66f31c5Sopenharmony_ci#if !defined(__NR_statx) || defined(__ANDROID_API__) && __ANDROID_API__ < 30 427e66f31c5Sopenharmony_ci return errno = ENOSYS, -1; 428e66f31c5Sopenharmony_ci#else 429e66f31c5Sopenharmony_ci int rc; 430e66f31c5Sopenharmony_ci 431e66f31c5Sopenharmony_ci rc = syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); 432e66f31c5Sopenharmony_ci if (rc >= 0) 433e66f31c5Sopenharmony_ci uv__msan_unpoison(statxbuf, sizeof(*statxbuf)); 434e66f31c5Sopenharmony_ci 435e66f31c5Sopenharmony_ci return rc; 436e66f31c5Sopenharmony_ci#endif 437e66f31c5Sopenharmony_ci} 438e66f31c5Sopenharmony_ci 439e66f31c5Sopenharmony_ci 440e66f31c5Sopenharmony_cissize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) { 441e66f31c5Sopenharmony_ci#if !defined(__NR_getrandom) || defined(__ANDROID_API__) && __ANDROID_API__ < 28 442e66f31c5Sopenharmony_ci return errno = ENOSYS, -1; 443e66f31c5Sopenharmony_ci#else 444e66f31c5Sopenharmony_ci ssize_t rc; 445e66f31c5Sopenharmony_ci 446e66f31c5Sopenharmony_ci rc = syscall(__NR_getrandom, buf, buflen, flags); 447e66f31c5Sopenharmony_ci if (rc >= 0) 448e66f31c5Sopenharmony_ci uv__msan_unpoison(buf, buflen); 449e66f31c5Sopenharmony_ci 450e66f31c5Sopenharmony_ci return rc; 451e66f31c5Sopenharmony_ci#endif 452e66f31c5Sopenharmony_ci} 453e66f31c5Sopenharmony_ci 454e66f31c5Sopenharmony_ci 455e66f31c5Sopenharmony_ciint uv__io_uring_setup(int entries, struct uv__io_uring_params* params) { 456e66f31c5Sopenharmony_ci return syscall(__NR_io_uring_setup, entries, params); 457e66f31c5Sopenharmony_ci} 458e66f31c5Sopenharmony_ci 459e66f31c5Sopenharmony_ci 460e66f31c5Sopenharmony_ciint uv__io_uring_enter(int fd, 461e66f31c5Sopenharmony_ci unsigned to_submit, 462e66f31c5Sopenharmony_ci unsigned min_complete, 463e66f31c5Sopenharmony_ci unsigned flags) { 464e66f31c5Sopenharmony_ci /* io_uring_enter used to take a sigset_t but it's unused 465e66f31c5Sopenharmony_ci * in newer kernels unless IORING_ENTER_EXT_ARG is set, 466e66f31c5Sopenharmony_ci * in which case it takes a struct io_uring_getevents_arg. 467e66f31c5Sopenharmony_ci */ 468e66f31c5Sopenharmony_ci return syscall(__NR_io_uring_enter, 469e66f31c5Sopenharmony_ci fd, 470e66f31c5Sopenharmony_ci to_submit, 471e66f31c5Sopenharmony_ci min_complete, 472e66f31c5Sopenharmony_ci flags, 473e66f31c5Sopenharmony_ci NULL, 474e66f31c5Sopenharmony_ci 0L); 475e66f31c5Sopenharmony_ci} 476e66f31c5Sopenharmony_ci 477e66f31c5Sopenharmony_ci 478e66f31c5Sopenharmony_ciint uv__io_uring_register(int fd, unsigned opcode, void* arg, unsigned nargs) { 479e66f31c5Sopenharmony_ci return syscall(__NR_io_uring_register, fd, opcode, arg, nargs); 480e66f31c5Sopenharmony_ci} 481e66f31c5Sopenharmony_ci 482e66f31c5Sopenharmony_ci 483e66f31c5Sopenharmony_cistatic int uv__use_io_uring(void) { 484e66f31c5Sopenharmony_ci#if defined(USE_OHOS_DFX) 485e66f31c5Sopenharmony_ci return 0; 486e66f31c5Sopenharmony_ci#endif 487e66f31c5Sopenharmony_ci#if defined(__ANDROID_API__) 488e66f31c5Sopenharmony_ci return 0; /* Possibly available but blocked by seccomp. */ 489e66f31c5Sopenharmony_ci#elif defined(__arm__) && __SIZEOF_POINTER__ == 4 490e66f31c5Sopenharmony_ci /* See https://github.com/libuv/libuv/issues/4158. */ 491e66f31c5Sopenharmony_ci return 0; /* All 32 bits kernels appear buggy. */ 492e66f31c5Sopenharmony_ci#elif defined(__powerpc64__) || defined(__ppc64__) 493e66f31c5Sopenharmony_ci /* See https://github.com/libuv/libuv/issues/4283. */ 494e66f31c5Sopenharmony_ci return 0; /* Random SIGSEGV in signal handler. */ 495e66f31c5Sopenharmony_ci#else 496e66f31c5Sopenharmony_ci /* Ternary: unknown=0, yes=1, no=-1 */ 497e66f31c5Sopenharmony_ci static _Atomic int use_io_uring; 498e66f31c5Sopenharmony_ci char* val; 499e66f31c5Sopenharmony_ci int use; 500e66f31c5Sopenharmony_ci 501e66f31c5Sopenharmony_ci use = atomic_load_explicit(&use_io_uring, memory_order_relaxed); 502e66f31c5Sopenharmony_ci 503e66f31c5Sopenharmony_ci if (use == 0) { 504e66f31c5Sopenharmony_ci use = uv__kernel_version() >= 505e66f31c5Sopenharmony_ci#if defined(__hppa__) 506e66f31c5Sopenharmony_ci /* io_uring first supported on parisc in 6.1, functional in .51 */ 507e66f31c5Sopenharmony_ci /* https://lore.kernel.org/all/cb912694-b1fe-dbb0-4d8c-d608f3526905@gmx.de/ */ 508e66f31c5Sopenharmony_ci /* 6.1.51 */ 0x060133 509e66f31c5Sopenharmony_ci#else 510e66f31c5Sopenharmony_ci /* Older kernels have a bug where the sqpoll thread uses 100% CPU. */ 511e66f31c5Sopenharmony_ci /* 5.10.186 */ 0x050ABA 512e66f31c5Sopenharmony_ci#endif 513e66f31c5Sopenharmony_ci ? 1 : -1; 514e66f31c5Sopenharmony_ci 515e66f31c5Sopenharmony_ci /* But users can still enable it if they so desire. */ 516e66f31c5Sopenharmony_ci val = getenv("UV_USE_IO_URING"); 517e66f31c5Sopenharmony_ci if (val != NULL) 518e66f31c5Sopenharmony_ci use = atoi(val) ? 1 : -1; 519e66f31c5Sopenharmony_ci 520e66f31c5Sopenharmony_ci atomic_store_explicit(&use_io_uring, use, memory_order_relaxed); 521e66f31c5Sopenharmony_ci } 522e66f31c5Sopenharmony_ci 523e66f31c5Sopenharmony_ci return use > 0; 524e66f31c5Sopenharmony_ci#endif 525e66f31c5Sopenharmony_ci} 526e66f31c5Sopenharmony_ci 527e66f31c5Sopenharmony_ci 528e66f31c5Sopenharmony_cistatic void uv__iou_init(int epollfd, 529e66f31c5Sopenharmony_ci struct uv__iou* iou, 530e66f31c5Sopenharmony_ci uint32_t entries, 531e66f31c5Sopenharmony_ci uint32_t flags) { 532e66f31c5Sopenharmony_ci struct uv__io_uring_params params; 533e66f31c5Sopenharmony_ci struct epoll_event e; 534e66f31c5Sopenharmony_ci size_t cqlen; 535e66f31c5Sopenharmony_ci size_t sqlen; 536e66f31c5Sopenharmony_ci size_t maxlen; 537e66f31c5Sopenharmony_ci size_t sqelen; 538e66f31c5Sopenharmony_ci uint32_t i; 539e66f31c5Sopenharmony_ci char* sq; 540e66f31c5Sopenharmony_ci char* sqe; 541e66f31c5Sopenharmony_ci int ringfd; 542e66f31c5Sopenharmony_ci 543e66f31c5Sopenharmony_ci sq = MAP_FAILED; 544e66f31c5Sopenharmony_ci sqe = MAP_FAILED; 545e66f31c5Sopenharmony_ci 546e66f31c5Sopenharmony_ci if (!uv__use_io_uring()) 547e66f31c5Sopenharmony_ci return; 548e66f31c5Sopenharmony_ci 549e66f31c5Sopenharmony_ci /* SQPOLL required CAP_SYS_NICE until linux v5.12 relaxed that requirement. 550e66f31c5Sopenharmony_ci * Mostly academic because we check for a v5.13 kernel afterwards anyway. 551e66f31c5Sopenharmony_ci */ 552e66f31c5Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 553e66f31c5Sopenharmony_ci params.flags = flags; 554e66f31c5Sopenharmony_ci 555e66f31c5Sopenharmony_ci if (flags & UV__IORING_SETUP_SQPOLL) 556e66f31c5Sopenharmony_ci params.sq_thread_idle = 10; /* milliseconds */ 557e66f31c5Sopenharmony_ci 558e66f31c5Sopenharmony_ci /* Kernel returns a file descriptor with O_CLOEXEC flag set. */ 559e66f31c5Sopenharmony_ci ringfd = uv__io_uring_setup(entries, ¶ms); 560e66f31c5Sopenharmony_ci if (ringfd == -1) 561e66f31c5Sopenharmony_ci return; 562e66f31c5Sopenharmony_ci 563e66f31c5Sopenharmony_ci /* IORING_FEAT_RSRC_TAGS is used to detect linux v5.13 but what we're 564e66f31c5Sopenharmony_ci * actually detecting is whether IORING_OP_STATX works with SQPOLL. 565e66f31c5Sopenharmony_ci */ 566e66f31c5Sopenharmony_ci if (!(params.features & UV__IORING_FEAT_RSRC_TAGS)) 567e66f31c5Sopenharmony_ci goto fail; 568e66f31c5Sopenharmony_ci 569e66f31c5Sopenharmony_ci /* Implied by IORING_FEAT_RSRC_TAGS but checked explicitly anyway. */ 570e66f31c5Sopenharmony_ci if (!(params.features & UV__IORING_FEAT_SINGLE_MMAP)) 571e66f31c5Sopenharmony_ci goto fail; 572e66f31c5Sopenharmony_ci 573e66f31c5Sopenharmony_ci /* Implied by IORING_FEAT_RSRC_TAGS but checked explicitly anyway. */ 574e66f31c5Sopenharmony_ci if (!(params.features & UV__IORING_FEAT_NODROP)) 575e66f31c5Sopenharmony_ci goto fail; 576e66f31c5Sopenharmony_ci 577e66f31c5Sopenharmony_ci sqlen = params.sq_off.array + params.sq_entries * sizeof(uint32_t); 578e66f31c5Sopenharmony_ci cqlen = 579e66f31c5Sopenharmony_ci params.cq_off.cqes + params.cq_entries * sizeof(struct uv__io_uring_cqe); 580e66f31c5Sopenharmony_ci maxlen = sqlen < cqlen ? cqlen : sqlen; 581e66f31c5Sopenharmony_ci sqelen = params.sq_entries * sizeof(struct uv__io_uring_sqe); 582e66f31c5Sopenharmony_ci 583e66f31c5Sopenharmony_ci sq = mmap(0, 584e66f31c5Sopenharmony_ci maxlen, 585e66f31c5Sopenharmony_ci PROT_READ | PROT_WRITE, 586e66f31c5Sopenharmony_ci MAP_SHARED | MAP_POPULATE, 587e66f31c5Sopenharmony_ci ringfd, 588e66f31c5Sopenharmony_ci 0); /* IORING_OFF_SQ_RING */ 589e66f31c5Sopenharmony_ci 590e66f31c5Sopenharmony_ci sqe = mmap(0, 591e66f31c5Sopenharmony_ci sqelen, 592e66f31c5Sopenharmony_ci PROT_READ | PROT_WRITE, 593e66f31c5Sopenharmony_ci MAP_SHARED | MAP_POPULATE, 594e66f31c5Sopenharmony_ci ringfd, 595e66f31c5Sopenharmony_ci 0x10000000ull); /* IORING_OFF_SQES */ 596e66f31c5Sopenharmony_ci 597e66f31c5Sopenharmony_ci if (sq == MAP_FAILED || sqe == MAP_FAILED) 598e66f31c5Sopenharmony_ci goto fail; 599e66f31c5Sopenharmony_ci 600e66f31c5Sopenharmony_ci if (flags & UV__IORING_SETUP_SQPOLL) { 601e66f31c5Sopenharmony_ci /* Only interested in completion events. To get notified when 602e66f31c5Sopenharmony_ci * the kernel pulls items from the submission ring, add POLLOUT. 603e66f31c5Sopenharmony_ci */ 604e66f31c5Sopenharmony_ci memset(&e, 0, sizeof(e)); 605e66f31c5Sopenharmony_ci e.events = POLLIN; 606e66f31c5Sopenharmony_ci e.data.fd = ringfd; 607e66f31c5Sopenharmony_ci 608e66f31c5Sopenharmony_ci if (uv__epoll_ctl(epollfd, EPOLL_CTL_ADD, ringfd, &e)) 609e66f31c5Sopenharmony_ci goto fail; 610e66f31c5Sopenharmony_ci } 611e66f31c5Sopenharmony_ci 612e66f31c5Sopenharmony_ci iou->sqhead = (uint32_t*) (sq + params.sq_off.head); 613e66f31c5Sopenharmony_ci iou->sqtail = (uint32_t*) (sq + params.sq_off.tail); 614e66f31c5Sopenharmony_ci iou->sqmask = *(uint32_t*) (sq + params.sq_off.ring_mask); 615e66f31c5Sopenharmony_ci iou->sqarray = (uint32_t*) (sq + params.sq_off.array); 616e66f31c5Sopenharmony_ci iou->sqflags = (uint32_t*) (sq + params.sq_off.flags); 617e66f31c5Sopenharmony_ci iou->cqhead = (uint32_t*) (sq + params.cq_off.head); 618e66f31c5Sopenharmony_ci iou->cqtail = (uint32_t*) (sq + params.cq_off.tail); 619e66f31c5Sopenharmony_ci iou->cqmask = *(uint32_t*) (sq + params.cq_off.ring_mask); 620e66f31c5Sopenharmony_ci iou->sq = sq; 621e66f31c5Sopenharmony_ci iou->cqe = sq + params.cq_off.cqes; 622e66f31c5Sopenharmony_ci iou->sqe = sqe; 623e66f31c5Sopenharmony_ci iou->sqlen = sqlen; 624e66f31c5Sopenharmony_ci iou->cqlen = cqlen; 625e66f31c5Sopenharmony_ci iou->maxlen = maxlen; 626e66f31c5Sopenharmony_ci iou->sqelen = sqelen; 627e66f31c5Sopenharmony_ci iou->ringfd = ringfd; 628e66f31c5Sopenharmony_ci iou->in_flight = 0; 629e66f31c5Sopenharmony_ci iou->flags = 0; 630e66f31c5Sopenharmony_ci 631e66f31c5Sopenharmony_ci if (uv__kernel_version() >= /* 5.15.0 */ 0x050F00) 632e66f31c5Sopenharmony_ci iou->flags |= UV__MKDIRAT_SYMLINKAT_LINKAT; 633e66f31c5Sopenharmony_ci 634e66f31c5Sopenharmony_ci for (i = 0; i <= iou->sqmask; i++) 635e66f31c5Sopenharmony_ci iou->sqarray[i] = i; /* Slot -> sqe identity mapping. */ 636e66f31c5Sopenharmony_ci 637e66f31c5Sopenharmony_ci return; 638e66f31c5Sopenharmony_ci 639e66f31c5Sopenharmony_cifail: 640e66f31c5Sopenharmony_ci if (sq != MAP_FAILED) 641e66f31c5Sopenharmony_ci munmap(sq, maxlen); 642e66f31c5Sopenharmony_ci 643e66f31c5Sopenharmony_ci if (sqe != MAP_FAILED) 644e66f31c5Sopenharmony_ci munmap(sqe, sqelen); 645e66f31c5Sopenharmony_ci 646e66f31c5Sopenharmony_ci uv__close(ringfd); 647e66f31c5Sopenharmony_ci} 648e66f31c5Sopenharmony_ci 649e66f31c5Sopenharmony_ci 650e66f31c5Sopenharmony_cistatic void uv__iou_delete(struct uv__iou* iou) { 651e66f31c5Sopenharmony_ci if (iou->ringfd != -1) { 652e66f31c5Sopenharmony_ci munmap(iou->sq, iou->maxlen); 653e66f31c5Sopenharmony_ci munmap(iou->sqe, iou->sqelen); 654e66f31c5Sopenharmony_ci uv__close(iou->ringfd); 655e66f31c5Sopenharmony_ci iou->ringfd = -1; 656e66f31c5Sopenharmony_ci } 657e66f31c5Sopenharmony_ci} 658e66f31c5Sopenharmony_ci 659e66f31c5Sopenharmony_ci 660e66f31c5Sopenharmony_ciint uv__platform_loop_init(uv_loop_t* loop) { 661e66f31c5Sopenharmony_ci uv__loop_internal_fields_t* lfields; 662e66f31c5Sopenharmony_ci 663e66f31c5Sopenharmony_ci lfields = uv__get_internal_fields(loop); 664e66f31c5Sopenharmony_ci lfields->ctl.ringfd = -1; 665e66f31c5Sopenharmony_ci lfields->iou.ringfd = -1; 666e66f31c5Sopenharmony_ci 667e66f31c5Sopenharmony_ci loop->inotify_watchers = NULL; 668e66f31c5Sopenharmony_ci loop->inotify_fd = -1; 669e66f31c5Sopenharmony_ci loop->backend_fd = epoll_create1(O_CLOEXEC); 670e66f31c5Sopenharmony_ci#ifdef USE_OHOS_DFX 671e66f31c5Sopenharmony_ci fdsan_exchange_owner_tag(loop->backend_fd, 0, uv__get_addr_tag((void *)&loop->backend_fd)); 672e66f31c5Sopenharmony_ci#endif 673e66f31c5Sopenharmony_ci if (loop->backend_fd == -1) 674e66f31c5Sopenharmony_ci return UV__ERR(errno); 675e66f31c5Sopenharmony_ci 676e66f31c5Sopenharmony_ci uv__iou_init(loop->backend_fd, &lfields->iou, 64, UV__IORING_SETUP_SQPOLL); 677e66f31c5Sopenharmony_ci uv__iou_init(loop->backend_fd, &lfields->ctl, 256, 0); 678e66f31c5Sopenharmony_ci UV_LOGI("init:%{public}zu, backend_fd:%{public}d", (size_t)loop, loop->backend_fd); 679e66f31c5Sopenharmony_ci return 0; 680e66f31c5Sopenharmony_ci} 681e66f31c5Sopenharmony_ci 682e66f31c5Sopenharmony_ci 683e66f31c5Sopenharmony_ciint uv__io_fork(uv_loop_t* loop) { 684e66f31c5Sopenharmony_ci int err; 685e66f31c5Sopenharmony_ci struct watcher_list* root; 686e66f31c5Sopenharmony_ci 687e66f31c5Sopenharmony_ci root = uv__inotify_watchers(loop)->rbh_root; 688e66f31c5Sopenharmony_ci#ifdef USE_OHOS_DFX 689e66f31c5Sopenharmony_ci fdsan_close_with_tag(loop->backend_fd, uv__get_addr_tag((void *)&loop->backend_fd)); 690e66f31c5Sopenharmony_ci#else 691e66f31c5Sopenharmony_ci uv__close(loop->backend_fd); 692e66f31c5Sopenharmony_ci#endif 693e66f31c5Sopenharmony_ci loop->backend_fd = -1; 694e66f31c5Sopenharmony_ci 695e66f31c5Sopenharmony_ci /* TODO(bnoordhuis) Loses items from the submission and completion rings. */ 696e66f31c5Sopenharmony_ci uv__platform_loop_delete(loop); 697e66f31c5Sopenharmony_ci 698e66f31c5Sopenharmony_ci err = uv__platform_loop_init(loop); 699e66f31c5Sopenharmony_ci if (err) 700e66f31c5Sopenharmony_ci return err; 701e66f31c5Sopenharmony_ci 702e66f31c5Sopenharmony_ci return uv__inotify_fork(loop, root); 703e66f31c5Sopenharmony_ci} 704e66f31c5Sopenharmony_ci 705e66f31c5Sopenharmony_ci 706e66f31c5Sopenharmony_civoid uv__platform_loop_delete(uv_loop_t* loop) { 707e66f31c5Sopenharmony_ci uv__loop_internal_fields_t* lfields; 708e66f31c5Sopenharmony_ci 709e66f31c5Sopenharmony_ci lfields = uv__get_internal_fields(loop); 710e66f31c5Sopenharmony_ci uv__iou_delete(&lfields->ctl); 711e66f31c5Sopenharmony_ci uv__iou_delete(&lfields->iou); 712e66f31c5Sopenharmony_ci 713e66f31c5Sopenharmony_ci if (loop->inotify_fd != -1) { 714e66f31c5Sopenharmony_ci uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); 715e66f31c5Sopenharmony_ci uv__close(loop->inotify_fd); 716e66f31c5Sopenharmony_ci loop->inotify_fd = -1; 717e66f31c5Sopenharmony_ci } 718e66f31c5Sopenharmony_ci} 719e66f31c5Sopenharmony_ci 720e66f31c5Sopenharmony_ci 721e66f31c5Sopenharmony_cistruct uv__invalidate { 722e66f31c5Sopenharmony_ci struct epoll_event (*prep)[256]; 723e66f31c5Sopenharmony_ci struct epoll_event* events; 724e66f31c5Sopenharmony_ci int nfds; 725e66f31c5Sopenharmony_ci}; 726e66f31c5Sopenharmony_ci 727e66f31c5Sopenharmony_ci 728e66f31c5Sopenharmony_civoid uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { 729e66f31c5Sopenharmony_ci uv__loop_internal_fields_t* lfields; 730e66f31c5Sopenharmony_ci struct uv__invalidate* inv; 731e66f31c5Sopenharmony_ci struct epoll_event dummy; 732e66f31c5Sopenharmony_ci int i; 733e66f31c5Sopenharmony_ci 734e66f31c5Sopenharmony_ci lfields = uv__get_internal_fields(loop); 735e66f31c5Sopenharmony_ci inv = lfields->inv; 736e66f31c5Sopenharmony_ci 737e66f31c5Sopenharmony_ci /* Invalidate events with same file descriptor */ 738e66f31c5Sopenharmony_ci if (inv != NULL) 739e66f31c5Sopenharmony_ci for (i = 0; i < inv->nfds; i++) 740e66f31c5Sopenharmony_ci if (inv->events[i].data.fd == fd) 741e66f31c5Sopenharmony_ci inv->events[i].data.fd = -1; 742e66f31c5Sopenharmony_ci 743e66f31c5Sopenharmony_ci /* Remove the file descriptor from the epoll. 744e66f31c5Sopenharmony_ci * This avoids a problem where the same file description remains open 745e66f31c5Sopenharmony_ci * in another process, causing repeated junk epoll events. 746e66f31c5Sopenharmony_ci * 747e66f31c5Sopenharmony_ci * We pass in a dummy epoll_event, to work around a bug in old kernels. 748e66f31c5Sopenharmony_ci * 749e66f31c5Sopenharmony_ci * Work around a bug in kernels 3.10 to 3.19 where passing a struct that 750e66f31c5Sopenharmony_ci * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. 751e66f31c5Sopenharmony_ci */ 752e66f31c5Sopenharmony_ci memset(&dummy, 0, sizeof(dummy)); 753e66f31c5Sopenharmony_ci 754e66f31c5Sopenharmony_ci if (inv == NULL) { 755e66f31c5Sopenharmony_ci uv__epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); 756e66f31c5Sopenharmony_ci } else { 757e66f31c5Sopenharmony_ci uv__epoll_ctl_prep(loop->backend_fd, 758e66f31c5Sopenharmony_ci &lfields->ctl, 759e66f31c5Sopenharmony_ci inv->prep, 760e66f31c5Sopenharmony_ci EPOLL_CTL_DEL, 761e66f31c5Sopenharmony_ci fd, 762e66f31c5Sopenharmony_ci &dummy); 763e66f31c5Sopenharmony_ci } 764e66f31c5Sopenharmony_ci} 765e66f31c5Sopenharmony_ci 766e66f31c5Sopenharmony_ci 767e66f31c5Sopenharmony_ciint uv__io_check_fd(uv_loop_t* loop, int fd) { 768e66f31c5Sopenharmony_ci struct epoll_event e; 769e66f31c5Sopenharmony_ci int rc; 770e66f31c5Sopenharmony_ci 771e66f31c5Sopenharmony_ci memset(&e, 0, sizeof(e)); 772e66f31c5Sopenharmony_ci e.events = POLLIN; 773e66f31c5Sopenharmony_ci e.data.fd = -1; 774e66f31c5Sopenharmony_ci 775e66f31c5Sopenharmony_ci rc = 0; 776e66f31c5Sopenharmony_ci if (uv__epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) 777e66f31c5Sopenharmony_ci if (errno != EEXIST) 778e66f31c5Sopenharmony_ci rc = UV__ERR(errno); 779e66f31c5Sopenharmony_ci 780e66f31c5Sopenharmony_ci if (rc == 0) 781e66f31c5Sopenharmony_ci if (uv__epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) 782e66f31c5Sopenharmony_ci abort(); 783e66f31c5Sopenharmony_ci 784e66f31c5Sopenharmony_ci return rc; 785e66f31c5Sopenharmony_ci} 786e66f31c5Sopenharmony_ci 787e66f31c5Sopenharmony_ci 788e66f31c5Sopenharmony_ci/* Caller must initialize SQE and call uv__iou_submit(). */ 789e66f31c5Sopenharmony_cistatic struct uv__io_uring_sqe* uv__iou_get_sqe(struct uv__iou* iou, 790e66f31c5Sopenharmony_ci uv_loop_t* loop, 791e66f31c5Sopenharmony_ci uv_fs_t* req) { 792e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 793e66f31c5Sopenharmony_ci uint32_t head; 794e66f31c5Sopenharmony_ci uint32_t tail; 795e66f31c5Sopenharmony_ci uint32_t mask; 796e66f31c5Sopenharmony_ci uint32_t slot; 797e66f31c5Sopenharmony_ci 798e66f31c5Sopenharmony_ci if (iou->ringfd == -1) 799e66f31c5Sopenharmony_ci return NULL; 800e66f31c5Sopenharmony_ci 801e66f31c5Sopenharmony_ci head = atomic_load_explicit((_Atomic uint32_t*) iou->sqhead, 802e66f31c5Sopenharmony_ci memory_order_acquire); 803e66f31c5Sopenharmony_ci tail = *iou->sqtail; 804e66f31c5Sopenharmony_ci mask = iou->sqmask; 805e66f31c5Sopenharmony_ci 806e66f31c5Sopenharmony_ci if ((head & mask) == ((tail + 1) & mask)) 807e66f31c5Sopenharmony_ci return NULL; /* No room in ring buffer. TODO(bnoordhuis) maybe flush it? */ 808e66f31c5Sopenharmony_ci 809e66f31c5Sopenharmony_ci slot = tail & mask; 810e66f31c5Sopenharmony_ci sqe = iou->sqe; 811e66f31c5Sopenharmony_ci sqe = &sqe[slot]; 812e66f31c5Sopenharmony_ci memset(sqe, 0, sizeof(*sqe)); 813e66f31c5Sopenharmony_ci sqe->user_data = (uintptr_t) req; 814e66f31c5Sopenharmony_ci 815e66f31c5Sopenharmony_ci /* Pacify uv_cancel(). */ 816e66f31c5Sopenharmony_ci req->work_req.loop = loop; 817e66f31c5Sopenharmony_ci req->work_req.work = NULL; 818e66f31c5Sopenharmony_ci req->work_req.done = NULL; 819e66f31c5Sopenharmony_ci uv__queue_init(&req->work_req.wq); 820e66f31c5Sopenharmony_ci 821e66f31c5Sopenharmony_ci uv__req_register(loop, req); 822e66f31c5Sopenharmony_ci iou->in_flight++; 823e66f31c5Sopenharmony_ci 824e66f31c5Sopenharmony_ci return sqe; 825e66f31c5Sopenharmony_ci} 826e66f31c5Sopenharmony_ci 827e66f31c5Sopenharmony_ci 828e66f31c5Sopenharmony_cistatic void uv__iou_submit(struct uv__iou* iou) { 829e66f31c5Sopenharmony_ci uint32_t flags; 830e66f31c5Sopenharmony_ci 831e66f31c5Sopenharmony_ci atomic_store_explicit((_Atomic uint32_t*) iou->sqtail, 832e66f31c5Sopenharmony_ci *iou->sqtail + 1, 833e66f31c5Sopenharmony_ci memory_order_release); 834e66f31c5Sopenharmony_ci 835e66f31c5Sopenharmony_ci flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags, 836e66f31c5Sopenharmony_ci memory_order_acquire); 837e66f31c5Sopenharmony_ci 838e66f31c5Sopenharmony_ci if (flags & UV__IORING_SQ_NEED_WAKEUP) 839e66f31c5Sopenharmony_ci if (uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_SQ_WAKEUP)) 840e66f31c5Sopenharmony_ci if (errno != EOWNERDEAD) /* Kernel bug. Harmless, ignore. */ 841e66f31c5Sopenharmony_ci perror("libuv: io_uring_enter(wakeup)"); /* Can't happen. */ 842e66f31c5Sopenharmony_ci} 843e66f31c5Sopenharmony_ci 844e66f31c5Sopenharmony_ci 845e66f31c5Sopenharmony_ciint uv__iou_fs_close(uv_loop_t* loop, uv_fs_t* req) { 846e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 847e66f31c5Sopenharmony_ci struct uv__iou* iou; 848e66f31c5Sopenharmony_ci int kv; 849e66f31c5Sopenharmony_ci 850e66f31c5Sopenharmony_ci kv = uv__kernel_version(); 851e66f31c5Sopenharmony_ci /* Work around a poorly understood bug in older kernels where closing a file 852e66f31c5Sopenharmony_ci * descriptor pointing to /foo/bar results in ETXTBSY errors when trying to 853e66f31c5Sopenharmony_ci * execve("/foo/bar") later on. The bug seems to have been fixed somewhere 854e66f31c5Sopenharmony_ci * between 5.15.85 and 5.15.90. I couldn't pinpoint the responsible commit 855e66f31c5Sopenharmony_ci * but good candidates are the several data race fixes. Interestingly, it 856e66f31c5Sopenharmony_ci * seems to manifest only when running under Docker so the possibility of 857e66f31c5Sopenharmony_ci * a Docker bug can't be completely ruled out either. Yay, computers. 858e66f31c5Sopenharmony_ci * Also, disable on non-longterm versions between 5.16.0 (non-longterm) and 859e66f31c5Sopenharmony_ci * 6.1.0 (longterm). Starting with longterm 6.1.x, the issue seems to be 860e66f31c5Sopenharmony_ci * solved. 861e66f31c5Sopenharmony_ci */ 862e66f31c5Sopenharmony_ci if (kv < /* 5.15.90 */ 0x050F5A) 863e66f31c5Sopenharmony_ci return 0; 864e66f31c5Sopenharmony_ci 865e66f31c5Sopenharmony_ci if (kv >= /* 5.16.0 */ 0x050A00 && kv < /* 6.1.0 */ 0x060100) 866e66f31c5Sopenharmony_ci return 0; 867e66f31c5Sopenharmony_ci 868e66f31c5Sopenharmony_ci 869e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 870e66f31c5Sopenharmony_ci 871e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 872e66f31c5Sopenharmony_ci if (sqe == NULL) 873e66f31c5Sopenharmony_ci return 0; 874e66f31c5Sopenharmony_ci 875e66f31c5Sopenharmony_ci sqe->fd = req->file; 876e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_CLOSE; 877e66f31c5Sopenharmony_ci 878e66f31c5Sopenharmony_ci uv__iou_submit(iou); 879e66f31c5Sopenharmony_ci 880e66f31c5Sopenharmony_ci return 1; 881e66f31c5Sopenharmony_ci} 882e66f31c5Sopenharmony_ci 883e66f31c5Sopenharmony_ci 884e66f31c5Sopenharmony_ciint uv__iou_fs_fsync_or_fdatasync(uv_loop_t* loop, 885e66f31c5Sopenharmony_ci uv_fs_t* req, 886e66f31c5Sopenharmony_ci uint32_t fsync_flags) { 887e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 888e66f31c5Sopenharmony_ci struct uv__iou* iou; 889e66f31c5Sopenharmony_ci 890e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 891e66f31c5Sopenharmony_ci 892e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 893e66f31c5Sopenharmony_ci if (sqe == NULL) 894e66f31c5Sopenharmony_ci return 0; 895e66f31c5Sopenharmony_ci 896e66f31c5Sopenharmony_ci /* Little known fact: setting seq->off and seq->len turns 897e66f31c5Sopenharmony_ci * it into an asynchronous sync_file_range() operation. 898e66f31c5Sopenharmony_ci */ 899e66f31c5Sopenharmony_ci sqe->fd = req->file; 900e66f31c5Sopenharmony_ci sqe->fsync_flags = fsync_flags; 901e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_FSYNC; 902e66f31c5Sopenharmony_ci 903e66f31c5Sopenharmony_ci uv__iou_submit(iou); 904e66f31c5Sopenharmony_ci 905e66f31c5Sopenharmony_ci return 1; 906e66f31c5Sopenharmony_ci} 907e66f31c5Sopenharmony_ci 908e66f31c5Sopenharmony_ci 909e66f31c5Sopenharmony_ciint uv__iou_fs_link(uv_loop_t* loop, uv_fs_t* req) { 910e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 911e66f31c5Sopenharmony_ci struct uv__iou* iou; 912e66f31c5Sopenharmony_ci 913e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 914e66f31c5Sopenharmony_ci 915e66f31c5Sopenharmony_ci if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) 916e66f31c5Sopenharmony_ci return 0; 917e66f31c5Sopenharmony_ci 918e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 919e66f31c5Sopenharmony_ci if (sqe == NULL) 920e66f31c5Sopenharmony_ci return 0; 921e66f31c5Sopenharmony_ci 922e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 923e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 924e66f31c5Sopenharmony_ci sqe->addr2 = (uintptr_t) req->new_path; 925e66f31c5Sopenharmony_ci sqe->len = AT_FDCWD; 926e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_LINKAT; 927e66f31c5Sopenharmony_ci 928e66f31c5Sopenharmony_ci uv__iou_submit(iou); 929e66f31c5Sopenharmony_ci 930e66f31c5Sopenharmony_ci return 1; 931e66f31c5Sopenharmony_ci} 932e66f31c5Sopenharmony_ci 933e66f31c5Sopenharmony_ci 934e66f31c5Sopenharmony_ciint uv__iou_fs_mkdir(uv_loop_t* loop, uv_fs_t* req) { 935e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 936e66f31c5Sopenharmony_ci struct uv__iou* iou; 937e66f31c5Sopenharmony_ci 938e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 939e66f31c5Sopenharmony_ci 940e66f31c5Sopenharmony_ci if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) 941e66f31c5Sopenharmony_ci return 0; 942e66f31c5Sopenharmony_ci 943e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 944e66f31c5Sopenharmony_ci if (sqe == NULL) 945e66f31c5Sopenharmony_ci return 0; 946e66f31c5Sopenharmony_ci 947e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 948e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 949e66f31c5Sopenharmony_ci sqe->len = req->mode; 950e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_MKDIRAT; 951e66f31c5Sopenharmony_ci 952e66f31c5Sopenharmony_ci uv__iou_submit(iou); 953e66f31c5Sopenharmony_ci 954e66f31c5Sopenharmony_ci return 1; 955e66f31c5Sopenharmony_ci} 956e66f31c5Sopenharmony_ci 957e66f31c5Sopenharmony_ci 958e66f31c5Sopenharmony_ciint uv__iou_fs_open(uv_loop_t* loop, uv_fs_t* req) { 959e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 960e66f31c5Sopenharmony_ci struct uv__iou* iou; 961e66f31c5Sopenharmony_ci 962e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 963e66f31c5Sopenharmony_ci 964e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 965e66f31c5Sopenharmony_ci if (sqe == NULL) 966e66f31c5Sopenharmony_ci return 0; 967e66f31c5Sopenharmony_ci 968e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 969e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 970e66f31c5Sopenharmony_ci sqe->len = req->mode; 971e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_OPENAT; 972e66f31c5Sopenharmony_ci sqe->open_flags = req->flags | O_CLOEXEC; 973e66f31c5Sopenharmony_ci 974e66f31c5Sopenharmony_ci uv__iou_submit(iou); 975e66f31c5Sopenharmony_ci 976e66f31c5Sopenharmony_ci return 1; 977e66f31c5Sopenharmony_ci} 978e66f31c5Sopenharmony_ci 979e66f31c5Sopenharmony_ci 980e66f31c5Sopenharmony_ciint uv__iou_fs_rename(uv_loop_t* loop, uv_fs_t* req) { 981e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 982e66f31c5Sopenharmony_ci struct uv__iou* iou; 983e66f31c5Sopenharmony_ci 984e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 985e66f31c5Sopenharmony_ci 986e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 987e66f31c5Sopenharmony_ci if (sqe == NULL) 988e66f31c5Sopenharmony_ci return 0; 989e66f31c5Sopenharmony_ci 990e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 991e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 992e66f31c5Sopenharmony_ci sqe->addr2 = (uintptr_t) req->new_path; 993e66f31c5Sopenharmony_ci sqe->len = AT_FDCWD; 994e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_RENAMEAT; 995e66f31c5Sopenharmony_ci 996e66f31c5Sopenharmony_ci uv__iou_submit(iou); 997e66f31c5Sopenharmony_ci 998e66f31c5Sopenharmony_ci return 1; 999e66f31c5Sopenharmony_ci} 1000e66f31c5Sopenharmony_ci 1001e66f31c5Sopenharmony_ci 1002e66f31c5Sopenharmony_ciint uv__iou_fs_symlink(uv_loop_t* loop, uv_fs_t* req) { 1003e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 1004e66f31c5Sopenharmony_ci struct uv__iou* iou; 1005e66f31c5Sopenharmony_ci 1006e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 1007e66f31c5Sopenharmony_ci 1008e66f31c5Sopenharmony_ci if (!(iou->flags & UV__MKDIRAT_SYMLINKAT_LINKAT)) 1009e66f31c5Sopenharmony_ci return 0; 1010e66f31c5Sopenharmony_ci 1011e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 1012e66f31c5Sopenharmony_ci if (sqe == NULL) 1013e66f31c5Sopenharmony_ci return 0; 1014e66f31c5Sopenharmony_ci 1015e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 1016e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 1017e66f31c5Sopenharmony_ci sqe->addr2 = (uintptr_t) req->new_path; 1018e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_SYMLINKAT; 1019e66f31c5Sopenharmony_ci 1020e66f31c5Sopenharmony_ci uv__iou_submit(iou); 1021e66f31c5Sopenharmony_ci 1022e66f31c5Sopenharmony_ci return 1; 1023e66f31c5Sopenharmony_ci} 1024e66f31c5Sopenharmony_ci 1025e66f31c5Sopenharmony_ci 1026e66f31c5Sopenharmony_ciint uv__iou_fs_unlink(uv_loop_t* loop, uv_fs_t* req) { 1027e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 1028e66f31c5Sopenharmony_ci struct uv__iou* iou; 1029e66f31c5Sopenharmony_ci 1030e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 1031e66f31c5Sopenharmony_ci 1032e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 1033e66f31c5Sopenharmony_ci if (sqe == NULL) 1034e66f31c5Sopenharmony_ci return 0; 1035e66f31c5Sopenharmony_ci 1036e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 1037e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 1038e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_UNLINKAT; 1039e66f31c5Sopenharmony_ci 1040e66f31c5Sopenharmony_ci uv__iou_submit(iou); 1041e66f31c5Sopenharmony_ci 1042e66f31c5Sopenharmony_ci return 1; 1043e66f31c5Sopenharmony_ci} 1044e66f31c5Sopenharmony_ci 1045e66f31c5Sopenharmony_ci 1046e66f31c5Sopenharmony_ciint uv__iou_fs_read_or_write(uv_loop_t* loop, 1047e66f31c5Sopenharmony_ci uv_fs_t* req, 1048e66f31c5Sopenharmony_ci int is_read) { 1049e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 1050e66f31c5Sopenharmony_ci struct uv__iou* iou; 1051e66f31c5Sopenharmony_ci 1052e66f31c5Sopenharmony_ci /* If iovcnt is greater than IOV_MAX, cap it to IOV_MAX on reads and fallback 1053e66f31c5Sopenharmony_ci * to the threadpool on writes */ 1054e66f31c5Sopenharmony_ci if (req->nbufs > IOV_MAX) { 1055e66f31c5Sopenharmony_ci if (is_read) 1056e66f31c5Sopenharmony_ci req->nbufs = IOV_MAX; 1057e66f31c5Sopenharmony_ci else 1058e66f31c5Sopenharmony_ci return 0; 1059e66f31c5Sopenharmony_ci } 1060e66f31c5Sopenharmony_ci 1061e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 1062e66f31c5Sopenharmony_ci 1063e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 1064e66f31c5Sopenharmony_ci if (sqe == NULL) 1065e66f31c5Sopenharmony_ci return 0; 1066e66f31c5Sopenharmony_ci 1067e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->bufs; 1068e66f31c5Sopenharmony_ci sqe->fd = req->file; 1069e66f31c5Sopenharmony_ci sqe->len = req->nbufs; 1070e66f31c5Sopenharmony_ci sqe->off = req->off < 0 ? -1 : req->off; 1071e66f31c5Sopenharmony_ci sqe->opcode = is_read ? UV__IORING_OP_READV : UV__IORING_OP_WRITEV; 1072e66f31c5Sopenharmony_ci 1073e66f31c5Sopenharmony_ci uv__iou_submit(iou); 1074e66f31c5Sopenharmony_ci 1075e66f31c5Sopenharmony_ci return 1; 1076e66f31c5Sopenharmony_ci} 1077e66f31c5Sopenharmony_ci 1078e66f31c5Sopenharmony_ci 1079e66f31c5Sopenharmony_ciint uv__iou_fs_statx(uv_loop_t* loop, 1080e66f31c5Sopenharmony_ci uv_fs_t* req, 1081e66f31c5Sopenharmony_ci int is_fstat, 1082e66f31c5Sopenharmony_ci int is_lstat) { 1083e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 1084e66f31c5Sopenharmony_ci struct uv__statx* statxbuf; 1085e66f31c5Sopenharmony_ci struct uv__iou* iou; 1086e66f31c5Sopenharmony_ci 1087e66f31c5Sopenharmony_ci statxbuf = uv__malloc(sizeof(*statxbuf)); 1088e66f31c5Sopenharmony_ci if (statxbuf == NULL) 1089e66f31c5Sopenharmony_ci return 0; 1090e66f31c5Sopenharmony_ci 1091e66f31c5Sopenharmony_ci iou = &uv__get_internal_fields(loop)->iou; 1092e66f31c5Sopenharmony_ci 1093e66f31c5Sopenharmony_ci sqe = uv__iou_get_sqe(iou, loop, req); 1094e66f31c5Sopenharmony_ci if (sqe == NULL) { 1095e66f31c5Sopenharmony_ci uv__free(statxbuf); 1096e66f31c5Sopenharmony_ci return 0; 1097e66f31c5Sopenharmony_ci } 1098e66f31c5Sopenharmony_ci 1099e66f31c5Sopenharmony_ci req->ptr = statxbuf; 1100e66f31c5Sopenharmony_ci 1101e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) req->path; 1102e66f31c5Sopenharmony_ci sqe->addr2 = (uintptr_t) statxbuf; 1103e66f31c5Sopenharmony_ci sqe->fd = AT_FDCWD; 1104e66f31c5Sopenharmony_ci sqe->len = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */ 1105e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_STATX; 1106e66f31c5Sopenharmony_ci 1107e66f31c5Sopenharmony_ci if (is_fstat) { 1108e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) ""; 1109e66f31c5Sopenharmony_ci sqe->fd = req->file; 1110e66f31c5Sopenharmony_ci sqe->statx_flags |= 0x1000; /* AT_EMPTY_PATH */ 1111e66f31c5Sopenharmony_ci } 1112e66f31c5Sopenharmony_ci 1113e66f31c5Sopenharmony_ci if (is_lstat) 1114e66f31c5Sopenharmony_ci sqe->statx_flags |= AT_SYMLINK_NOFOLLOW; 1115e66f31c5Sopenharmony_ci 1116e66f31c5Sopenharmony_ci uv__iou_submit(iou); 1117e66f31c5Sopenharmony_ci 1118e66f31c5Sopenharmony_ci return 1; 1119e66f31c5Sopenharmony_ci} 1120e66f31c5Sopenharmony_ci 1121e66f31c5Sopenharmony_ci 1122e66f31c5Sopenharmony_civoid uv__statx_to_stat(const struct uv__statx* statxbuf, uv_stat_t* buf) { 1123e66f31c5Sopenharmony_ci buf->st_dev = makedev(statxbuf->stx_dev_major, statxbuf->stx_dev_minor); 1124e66f31c5Sopenharmony_ci buf->st_mode = statxbuf->stx_mode; 1125e66f31c5Sopenharmony_ci buf->st_nlink = statxbuf->stx_nlink; 1126e66f31c5Sopenharmony_ci buf->st_uid = statxbuf->stx_uid; 1127e66f31c5Sopenharmony_ci buf->st_gid = statxbuf->stx_gid; 1128e66f31c5Sopenharmony_ci buf->st_rdev = makedev(statxbuf->stx_rdev_major, statxbuf->stx_rdev_minor); 1129e66f31c5Sopenharmony_ci buf->st_ino = statxbuf->stx_ino; 1130e66f31c5Sopenharmony_ci buf->st_size = statxbuf->stx_size; 1131e66f31c5Sopenharmony_ci buf->st_blksize = statxbuf->stx_blksize; 1132e66f31c5Sopenharmony_ci buf->st_blocks = statxbuf->stx_blocks; 1133e66f31c5Sopenharmony_ci buf->st_atim.tv_sec = statxbuf->stx_atime.tv_sec; 1134e66f31c5Sopenharmony_ci buf->st_atim.tv_nsec = statxbuf->stx_atime.tv_nsec; 1135e66f31c5Sopenharmony_ci buf->st_mtim.tv_sec = statxbuf->stx_mtime.tv_sec; 1136e66f31c5Sopenharmony_ci buf->st_mtim.tv_nsec = statxbuf->stx_mtime.tv_nsec; 1137e66f31c5Sopenharmony_ci buf->st_ctim.tv_sec = statxbuf->stx_ctime.tv_sec; 1138e66f31c5Sopenharmony_ci buf->st_ctim.tv_nsec = statxbuf->stx_ctime.tv_nsec; 1139e66f31c5Sopenharmony_ci buf->st_birthtim.tv_sec = statxbuf->stx_btime.tv_sec; 1140e66f31c5Sopenharmony_ci buf->st_birthtim.tv_nsec = statxbuf->stx_btime.tv_nsec; 1141e66f31c5Sopenharmony_ci buf->st_flags = 0; 1142e66f31c5Sopenharmony_ci buf->st_gen = 0; 1143e66f31c5Sopenharmony_ci} 1144e66f31c5Sopenharmony_ci 1145e66f31c5Sopenharmony_ci 1146e66f31c5Sopenharmony_cistatic void uv__iou_fs_statx_post(uv_fs_t* req) { 1147e66f31c5Sopenharmony_ci struct uv__statx* statxbuf; 1148e66f31c5Sopenharmony_ci uv_stat_t* buf; 1149e66f31c5Sopenharmony_ci 1150e66f31c5Sopenharmony_ci buf = &req->statbuf; 1151e66f31c5Sopenharmony_ci statxbuf = req->ptr; 1152e66f31c5Sopenharmony_ci req->ptr = NULL; 1153e66f31c5Sopenharmony_ci 1154e66f31c5Sopenharmony_ci if (req->result == 0) { 1155e66f31c5Sopenharmony_ci uv__msan_unpoison(statxbuf, sizeof(*statxbuf)); 1156e66f31c5Sopenharmony_ci uv__statx_to_stat(statxbuf, buf); 1157e66f31c5Sopenharmony_ci req->ptr = buf; 1158e66f31c5Sopenharmony_ci } 1159e66f31c5Sopenharmony_ci 1160e66f31c5Sopenharmony_ci uv__free(statxbuf); 1161e66f31c5Sopenharmony_ci} 1162e66f31c5Sopenharmony_ci 1163e66f31c5Sopenharmony_ci 1164e66f31c5Sopenharmony_cistatic void uv__poll_io_uring(uv_loop_t* loop, struct uv__iou* iou) { 1165e66f31c5Sopenharmony_ci struct uv__io_uring_cqe* cqe; 1166e66f31c5Sopenharmony_ci struct uv__io_uring_cqe* e; 1167e66f31c5Sopenharmony_ci uv_fs_t* req; 1168e66f31c5Sopenharmony_ci uint32_t head; 1169e66f31c5Sopenharmony_ci uint32_t tail; 1170e66f31c5Sopenharmony_ci uint32_t mask; 1171e66f31c5Sopenharmony_ci uint32_t i; 1172e66f31c5Sopenharmony_ci uint32_t flags; 1173e66f31c5Sopenharmony_ci int nevents; 1174e66f31c5Sopenharmony_ci int rc; 1175e66f31c5Sopenharmony_ci 1176e66f31c5Sopenharmony_ci head = *iou->cqhead; 1177e66f31c5Sopenharmony_ci tail = atomic_load_explicit((_Atomic uint32_t*) iou->cqtail, 1178e66f31c5Sopenharmony_ci memory_order_acquire); 1179e66f31c5Sopenharmony_ci mask = iou->cqmask; 1180e66f31c5Sopenharmony_ci cqe = iou->cqe; 1181e66f31c5Sopenharmony_ci nevents = 0; 1182e66f31c5Sopenharmony_ci 1183e66f31c5Sopenharmony_ci for (i = head; i != tail; i++) { 1184e66f31c5Sopenharmony_ci e = &cqe[i & mask]; 1185e66f31c5Sopenharmony_ci 1186e66f31c5Sopenharmony_ci req = (uv_fs_t*) (uintptr_t) e->user_data; 1187e66f31c5Sopenharmony_ci assert(req->type == UV_FS); 1188e66f31c5Sopenharmony_ci 1189e66f31c5Sopenharmony_ci uv__req_unregister(loop, req); 1190e66f31c5Sopenharmony_ci iou->in_flight--; 1191e66f31c5Sopenharmony_ci 1192e66f31c5Sopenharmony_ci /* If the op is not supported by the kernel retry using the thread pool */ 1193e66f31c5Sopenharmony_ci if (e->res == -EOPNOTSUPP) { 1194e66f31c5Sopenharmony_ci uv__fs_post(loop, req); 1195e66f31c5Sopenharmony_ci continue; 1196e66f31c5Sopenharmony_ci } 1197e66f31c5Sopenharmony_ci 1198e66f31c5Sopenharmony_ci /* io_uring stores error codes as negative numbers, same as libuv. */ 1199e66f31c5Sopenharmony_ci req->result = e->res; 1200e66f31c5Sopenharmony_ci 1201e66f31c5Sopenharmony_ci switch (req->fs_type) { 1202e66f31c5Sopenharmony_ci case UV_FS_FSTAT: 1203e66f31c5Sopenharmony_ci case UV_FS_LSTAT: 1204e66f31c5Sopenharmony_ci case UV_FS_STAT: 1205e66f31c5Sopenharmony_ci uv__iou_fs_statx_post(req); 1206e66f31c5Sopenharmony_ci break; 1207e66f31c5Sopenharmony_ci default: /* Squelch -Wswitch warnings. */ 1208e66f31c5Sopenharmony_ci break; 1209e66f31c5Sopenharmony_ci } 1210e66f31c5Sopenharmony_ci 1211e66f31c5Sopenharmony_ci uv__metrics_update_idle_time(loop); 1212e66f31c5Sopenharmony_ci req->cb(req); 1213e66f31c5Sopenharmony_ci nevents++; 1214e66f31c5Sopenharmony_ci } 1215e66f31c5Sopenharmony_ci 1216e66f31c5Sopenharmony_ci atomic_store_explicit((_Atomic uint32_t*) iou->cqhead, 1217e66f31c5Sopenharmony_ci tail, 1218e66f31c5Sopenharmony_ci memory_order_release); 1219e66f31c5Sopenharmony_ci 1220e66f31c5Sopenharmony_ci /* Check whether CQE's overflowed, if so enter the kernel to make them 1221e66f31c5Sopenharmony_ci * available. Don't grab them immediately but in the next loop iteration to 1222e66f31c5Sopenharmony_ci * avoid loop starvation. */ 1223e66f31c5Sopenharmony_ci flags = atomic_load_explicit((_Atomic uint32_t*) iou->sqflags, 1224e66f31c5Sopenharmony_ci memory_order_acquire); 1225e66f31c5Sopenharmony_ci 1226e66f31c5Sopenharmony_ci if (flags & UV__IORING_SQ_CQ_OVERFLOW) { 1227e66f31c5Sopenharmony_ci do 1228e66f31c5Sopenharmony_ci rc = uv__io_uring_enter(iou->ringfd, 0, 0, UV__IORING_ENTER_GETEVENTS); 1229e66f31c5Sopenharmony_ci while (rc == -1 && errno == EINTR); 1230e66f31c5Sopenharmony_ci 1231e66f31c5Sopenharmony_ci if (rc < 0) 1232e66f31c5Sopenharmony_ci perror("libuv: io_uring_enter(getevents)"); /* Can't happen. */ 1233e66f31c5Sopenharmony_ci } 1234e66f31c5Sopenharmony_ci 1235e66f31c5Sopenharmony_ci uv__metrics_inc_events(loop, nevents); 1236e66f31c5Sopenharmony_ci if (uv__get_internal_fields(loop)->current_timeout == 0) 1237e66f31c5Sopenharmony_ci uv__metrics_inc_events_waiting(loop, nevents); 1238e66f31c5Sopenharmony_ci} 1239e66f31c5Sopenharmony_ci 1240e66f31c5Sopenharmony_ci 1241e66f31c5Sopenharmony_cistatic void uv__epoll_ctl_prep(int epollfd, 1242e66f31c5Sopenharmony_ci struct uv__iou* ctl, 1243e66f31c5Sopenharmony_ci struct epoll_event (*events)[256], 1244e66f31c5Sopenharmony_ci int op, 1245e66f31c5Sopenharmony_ci int fd, 1246e66f31c5Sopenharmony_ci struct epoll_event* e) { 1247e66f31c5Sopenharmony_ci struct uv__io_uring_sqe* sqe; 1248e66f31c5Sopenharmony_ci struct epoll_event* pe; 1249e66f31c5Sopenharmony_ci uint32_t mask; 1250e66f31c5Sopenharmony_ci uint32_t slot; 1251e66f31c5Sopenharmony_ci int ret = 0; 1252e66f31c5Sopenharmony_ci 1253e66f31c5Sopenharmony_ci if (ctl->ringfd == -1) { 1254e66f31c5Sopenharmony_ci if (!uv__epoll_ctl(epollfd, op, fd, e)) 1255e66f31c5Sopenharmony_ci return; 1256e66f31c5Sopenharmony_ci 1257e66f31c5Sopenharmony_ci if (op == EPOLL_CTL_DEL) 1258e66f31c5Sopenharmony_ci return; /* Ignore errors, may be racing with another thread. */ 1259e66f31c5Sopenharmony_ci 1260e66f31c5Sopenharmony_ci if (op != EPOLL_CTL_ADD) { 1261e66f31c5Sopenharmony_ci#ifdef PRINT_ERRNO_ABORT 1262e66f31c5Sopenharmony_ci UV_ERRNO_ABORT("errno is %d, fd is %d, backend_fd is %d(%s:%s:%d)", 1263e66f31c5Sopenharmony_ci errno, fd, epollfd, __FILE__, __func__, __LINE__); 1264e66f31c5Sopenharmony_ci#else 1265e66f31c5Sopenharmony_ci abort(); 1266e66f31c5Sopenharmony_ci#endif 1267e66f31c5Sopenharmony_ci } 1268e66f31c5Sopenharmony_ci 1269e66f31c5Sopenharmony_ci if (errno != EEXIST) { 1270e66f31c5Sopenharmony_ci#ifdef PRINT_ERRNO_ABORT 1271e66f31c5Sopenharmony_ci UV_ERRNO_ABORT("errno is %d, fd is %d, backend_fd is %d(%s:%s:%d)", 1272e66f31c5Sopenharmony_ci errno, fd, epollfd, __FILE__, __func__, __LINE__); 1273e66f31c5Sopenharmony_ci#else 1274e66f31c5Sopenharmony_ci abort(); 1275e66f31c5Sopenharmony_ci#endif 1276e66f31c5Sopenharmony_ci } 1277e66f31c5Sopenharmony_ci 1278e66f31c5Sopenharmony_ci /* File descriptor that's been watched before, update event mask. */ 1279e66f31c5Sopenharmony_ci ret = uv__epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, e); 1280e66f31c5Sopenharmony_ci if (!ret) 1281e66f31c5Sopenharmony_ci return; 1282e66f31c5Sopenharmony_ci 1283e66f31c5Sopenharmony_ci#ifdef PRINT_ERRNO_ABORT 1284e66f31c5Sopenharmony_ci UV_ERRNO_ABORT("errno is %d, uv__epoll_ctl ret is %d, fd is %d, backend_fd is %d(%s:%s:%d)", 1285e66f31c5Sopenharmony_ci errno, ret, fd, epollfd, __FILE__, __func__, __LINE__); 1286e66f31c5Sopenharmony_ci#else 1287e66f31c5Sopenharmony_ci abort(); 1288e66f31c5Sopenharmony_ci#endif 1289e66f31c5Sopenharmony_ci } else { 1290e66f31c5Sopenharmony_ci mask = ctl->sqmask; 1291e66f31c5Sopenharmony_ci slot = (*ctl->sqtail)++ & mask; 1292e66f31c5Sopenharmony_ci 1293e66f31c5Sopenharmony_ci pe = &(*events)[slot]; 1294e66f31c5Sopenharmony_ci *pe = *e; 1295e66f31c5Sopenharmony_ci 1296e66f31c5Sopenharmony_ci sqe = ctl->sqe; 1297e66f31c5Sopenharmony_ci sqe = &sqe[slot]; 1298e66f31c5Sopenharmony_ci 1299e66f31c5Sopenharmony_ci memset(sqe, 0, sizeof(*sqe)); 1300e66f31c5Sopenharmony_ci sqe->addr = (uintptr_t) pe; 1301e66f31c5Sopenharmony_ci sqe->fd = epollfd; 1302e66f31c5Sopenharmony_ci sqe->len = op; 1303e66f31c5Sopenharmony_ci sqe->off = fd; 1304e66f31c5Sopenharmony_ci sqe->opcode = UV__IORING_OP_EPOLL_CTL; 1305e66f31c5Sopenharmony_ci sqe->user_data = op | slot << 2 | (int64_t) fd << 32; 1306e66f31c5Sopenharmony_ci 1307e66f31c5Sopenharmony_ci if ((*ctl->sqhead & mask) == (*ctl->sqtail & mask)) 1308e66f31c5Sopenharmony_ci uv__epoll_ctl_flush(epollfd, ctl, events); 1309e66f31c5Sopenharmony_ci } 1310e66f31c5Sopenharmony_ci} 1311e66f31c5Sopenharmony_ci 1312e66f31c5Sopenharmony_ci 1313e66f31c5Sopenharmony_cistatic void uv__epoll_ctl_flush(int epollfd, 1314e66f31c5Sopenharmony_ci struct uv__iou* ctl, 1315e66f31c5Sopenharmony_ci struct epoll_event (*events)[256]) { 1316e66f31c5Sopenharmony_ci struct epoll_event oldevents[256]; 1317e66f31c5Sopenharmony_ci struct uv__io_uring_cqe* cqe; 1318e66f31c5Sopenharmony_ci uint32_t oldslot; 1319e66f31c5Sopenharmony_ci uint32_t slot; 1320e66f31c5Sopenharmony_ci uint32_t n; 1321e66f31c5Sopenharmony_ci int fd; 1322e66f31c5Sopenharmony_ci int op; 1323e66f31c5Sopenharmony_ci int rc; 1324e66f31c5Sopenharmony_ci 1325e66f31c5Sopenharmony_ci STATIC_ASSERT(sizeof(oldevents) == sizeof(*events)); 1326e66f31c5Sopenharmony_ci assert(ctl->ringfd != -1); 1327e66f31c5Sopenharmony_ci assert(*ctl->sqhead != *ctl->sqtail); 1328e66f31c5Sopenharmony_ci 1329e66f31c5Sopenharmony_ci n = *ctl->sqtail - *ctl->sqhead; 1330e66f31c5Sopenharmony_ci do 1331e66f31c5Sopenharmony_ci rc = uv__io_uring_enter(ctl->ringfd, n, n, UV__IORING_ENTER_GETEVENTS); 1332e66f31c5Sopenharmony_ci while (rc == -1 && errno == EINTR); 1333e66f31c5Sopenharmony_ci 1334e66f31c5Sopenharmony_ci if (rc < 0) 1335e66f31c5Sopenharmony_ci perror("libuv: io_uring_enter(getevents)"); /* Can't happen. */ 1336e66f31c5Sopenharmony_ci 1337e66f31c5Sopenharmony_ci if (rc != (int) n) 1338e66f31c5Sopenharmony_ci abort(); 1339e66f31c5Sopenharmony_ci 1340e66f31c5Sopenharmony_ci assert(*ctl->sqhead == *ctl->sqtail); 1341e66f31c5Sopenharmony_ci 1342e66f31c5Sopenharmony_ci memcpy(oldevents, *events, sizeof(*events)); 1343e66f31c5Sopenharmony_ci 1344e66f31c5Sopenharmony_ci /* Failed submissions are either EPOLL_CTL_DEL commands for file descriptors 1345e66f31c5Sopenharmony_ci * that have been closed, or EPOLL_CTL_ADD commands for file descriptors 1346e66f31c5Sopenharmony_ci * that we are already watching. Ignore the former and retry the latter 1347e66f31c5Sopenharmony_ci * with EPOLL_CTL_MOD. 1348e66f31c5Sopenharmony_ci */ 1349e66f31c5Sopenharmony_ci while (*ctl->cqhead != *ctl->cqtail) { 1350e66f31c5Sopenharmony_ci slot = (*ctl->cqhead)++ & ctl->cqmask; 1351e66f31c5Sopenharmony_ci 1352e66f31c5Sopenharmony_ci cqe = ctl->cqe; 1353e66f31c5Sopenharmony_ci cqe = &cqe[slot]; 1354e66f31c5Sopenharmony_ci 1355e66f31c5Sopenharmony_ci if (cqe->res == 0) 1356e66f31c5Sopenharmony_ci continue; 1357e66f31c5Sopenharmony_ci 1358e66f31c5Sopenharmony_ci fd = cqe->user_data >> 32; 1359e66f31c5Sopenharmony_ci op = 3 & cqe->user_data; 1360e66f31c5Sopenharmony_ci oldslot = 255 & (cqe->user_data >> 2); 1361e66f31c5Sopenharmony_ci 1362e66f31c5Sopenharmony_ci if (op == EPOLL_CTL_DEL) 1363e66f31c5Sopenharmony_ci continue; 1364e66f31c5Sopenharmony_ci 1365e66f31c5Sopenharmony_ci if (op != EPOLL_CTL_ADD) 1366e66f31c5Sopenharmony_ci abort(); 1367e66f31c5Sopenharmony_ci 1368e66f31c5Sopenharmony_ci if (cqe->res != -EEXIST) 1369e66f31c5Sopenharmony_ci abort(); 1370e66f31c5Sopenharmony_ci 1371e66f31c5Sopenharmony_ci uv__epoll_ctl_prep(epollfd, 1372e66f31c5Sopenharmony_ci ctl, 1373e66f31c5Sopenharmony_ci events, 1374e66f31c5Sopenharmony_ci EPOLL_CTL_MOD, 1375e66f31c5Sopenharmony_ci fd, 1376e66f31c5Sopenharmony_ci &oldevents[oldslot]); 1377e66f31c5Sopenharmony_ci } 1378e66f31c5Sopenharmony_ci} 1379e66f31c5Sopenharmony_ci 1380e66f31c5Sopenharmony_ci 1381e66f31c5Sopenharmony_civoid uv__io_poll(uv_loop_t* loop, int timeout) { 1382e66f31c5Sopenharmony_ci uv__loop_internal_fields_t* lfields; 1383e66f31c5Sopenharmony_ci struct epoll_event events[1024]; 1384e66f31c5Sopenharmony_ci struct epoll_event prep[256]; 1385e66f31c5Sopenharmony_ci struct uv__invalidate inv; 1386e66f31c5Sopenharmony_ci struct epoll_event* pe; 1387e66f31c5Sopenharmony_ci struct epoll_event e; 1388e66f31c5Sopenharmony_ci struct uv__iou* ctl; 1389e66f31c5Sopenharmony_ci struct uv__iou* iou; 1390e66f31c5Sopenharmony_ci int real_timeout; 1391e66f31c5Sopenharmony_ci struct uv__queue* q; 1392e66f31c5Sopenharmony_ci uv__io_t* w; 1393e66f31c5Sopenharmony_ci sigset_t* sigmask; 1394e66f31c5Sopenharmony_ci sigset_t sigset; 1395e66f31c5Sopenharmony_ci uint64_t base; 1396e66f31c5Sopenharmony_ci int have_iou_events; 1397e66f31c5Sopenharmony_ci int have_signals; 1398e66f31c5Sopenharmony_ci int nevents; 1399e66f31c5Sopenharmony_ci int epollfd; 1400e66f31c5Sopenharmony_ci int count; 1401e66f31c5Sopenharmony_ci int nfds; 1402e66f31c5Sopenharmony_ci int fd; 1403e66f31c5Sopenharmony_ci int op; 1404e66f31c5Sopenharmony_ci int i; 1405e66f31c5Sopenharmony_ci int user_timeout; 1406e66f31c5Sopenharmony_ci int reset_timeout; 1407e66f31c5Sopenharmony_ci 1408e66f31c5Sopenharmony_ci lfields = uv__get_internal_fields(loop); 1409e66f31c5Sopenharmony_ci ctl = &lfields->ctl; 1410e66f31c5Sopenharmony_ci iou = &lfields->iou; 1411e66f31c5Sopenharmony_ci 1412e66f31c5Sopenharmony_ci sigmask = NULL; 1413e66f31c5Sopenharmony_ci if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { 1414e66f31c5Sopenharmony_ci sigemptyset(&sigset); 1415e66f31c5Sopenharmony_ci sigaddset(&sigset, SIGPROF); 1416e66f31c5Sopenharmony_ci sigmask = &sigset; 1417e66f31c5Sopenharmony_ci } 1418e66f31c5Sopenharmony_ci 1419e66f31c5Sopenharmony_ci assert(timeout >= -1); 1420e66f31c5Sopenharmony_ci base = loop->time; 1421e66f31c5Sopenharmony_ci count = 48; /* Benchmarks suggest this gives the best throughput. */ 1422e66f31c5Sopenharmony_ci real_timeout = timeout; 1423e66f31c5Sopenharmony_ci 1424e66f31c5Sopenharmony_ci if (lfields->flags & UV_METRICS_IDLE_TIME) { 1425e66f31c5Sopenharmony_ci reset_timeout = 1; 1426e66f31c5Sopenharmony_ci user_timeout = timeout; 1427e66f31c5Sopenharmony_ci timeout = 0; 1428e66f31c5Sopenharmony_ci } else { 1429e66f31c5Sopenharmony_ci reset_timeout = 0; 1430e66f31c5Sopenharmony_ci user_timeout = 0; 1431e66f31c5Sopenharmony_ci } 1432e66f31c5Sopenharmony_ci 1433e66f31c5Sopenharmony_ci epollfd = loop->backend_fd; 1434e66f31c5Sopenharmony_ci 1435e66f31c5Sopenharmony_ci memset(&e, 0, sizeof(e)); 1436e66f31c5Sopenharmony_ci 1437e66f31c5Sopenharmony_ci while (!uv__queue_empty(&loop->watcher_queue)) { 1438e66f31c5Sopenharmony_ci q = uv__queue_head(&loop->watcher_queue); 1439e66f31c5Sopenharmony_ci w = uv__queue_data(q, uv__io_t, watcher_queue); 1440e66f31c5Sopenharmony_ci uv__queue_remove(q); 1441e66f31c5Sopenharmony_ci uv__queue_init(q); 1442e66f31c5Sopenharmony_ci 1443e66f31c5Sopenharmony_ci op = EPOLL_CTL_MOD; 1444e66f31c5Sopenharmony_ci if (w->events == 0) 1445e66f31c5Sopenharmony_ci op = EPOLL_CTL_ADD; 1446e66f31c5Sopenharmony_ci 1447e66f31c5Sopenharmony_ci w->events = w->pevents; 1448e66f31c5Sopenharmony_ci e.events = w->pevents; 1449e66f31c5Sopenharmony_ci e.data.fd = w->fd; 1450e66f31c5Sopenharmony_ci 1451e66f31c5Sopenharmony_ci uv__epoll_ctl_prep(epollfd, ctl, &prep, op, w->fd, &e); 1452e66f31c5Sopenharmony_ci } 1453e66f31c5Sopenharmony_ci 1454e66f31c5Sopenharmony_ci inv.events = events; 1455e66f31c5Sopenharmony_ci inv.prep = &prep; 1456e66f31c5Sopenharmony_ci inv.nfds = -1; 1457e66f31c5Sopenharmony_ci 1458e66f31c5Sopenharmony_ci for (;;) { 1459e66f31c5Sopenharmony_ci if (loop->nfds == 0) 1460e66f31c5Sopenharmony_ci if (iou->in_flight == 0) 1461e66f31c5Sopenharmony_ci break; 1462e66f31c5Sopenharmony_ci 1463e66f31c5Sopenharmony_ci /* All event mask mutations should be visible to the kernel before 1464e66f31c5Sopenharmony_ci * we enter epoll_pwait(). 1465e66f31c5Sopenharmony_ci */ 1466e66f31c5Sopenharmony_ci if (ctl->ringfd != -1) 1467e66f31c5Sopenharmony_ci while (*ctl->sqhead != *ctl->sqtail) 1468e66f31c5Sopenharmony_ci uv__epoll_ctl_flush(epollfd, ctl, &prep); 1469e66f31c5Sopenharmony_ci 1470e66f31c5Sopenharmony_ci /* Only need to set the provider_entry_time if timeout != 0. The function 1471e66f31c5Sopenharmony_ci * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME. 1472e66f31c5Sopenharmony_ci */ 1473e66f31c5Sopenharmony_ci if (timeout != 0) 1474e66f31c5Sopenharmony_ci uv__metrics_set_provider_entry_time(loop); 1475e66f31c5Sopenharmony_ci 1476e66f31c5Sopenharmony_ci /* Store the current timeout in a location that's globally accessible so 1477e66f31c5Sopenharmony_ci * other locations like uv__work_done() can determine whether the queue 1478e66f31c5Sopenharmony_ci * of events in the callback were waiting when poll was called. 1479e66f31c5Sopenharmony_ci */ 1480e66f31c5Sopenharmony_ci lfields->current_timeout = timeout; 1481e66f31c5Sopenharmony_ci#ifdef USE_FFRT 1482e66f31c5Sopenharmony_ci if (ffrt_get_cur_task() == NULL) { 1483e66f31c5Sopenharmony_ci nfds = epoll_pwait(epollfd, events, ARRAY_SIZE(events), timeout, sigmask); 1484e66f31c5Sopenharmony_ci } else { 1485e66f31c5Sopenharmony_ci nfds = uv__epoll_wait(events, ARRAY_SIZE(events), timeout); 1486e66f31c5Sopenharmony_ci } 1487e66f31c5Sopenharmony_ci#else 1488e66f31c5Sopenharmony_ci nfds = epoll_pwait(epollfd, events, ARRAY_SIZE(events), timeout, sigmask); 1489e66f31c5Sopenharmony_ci#endif 1490e66f31c5Sopenharmony_ci 1491e66f31c5Sopenharmony_ci /* Update loop->time unconditionally. It's tempting to skip the update when 1492e66f31c5Sopenharmony_ci * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the 1493e66f31c5Sopenharmony_ci * operating system didn't reschedule our process while in the syscall. 1494e66f31c5Sopenharmony_ci */ 1495e66f31c5Sopenharmony_ci SAVE_ERRNO(uv__update_time(loop)); 1496e66f31c5Sopenharmony_ci 1497e66f31c5Sopenharmony_ci if (nfds == -1) 1498e66f31c5Sopenharmony_ci assert(errno == EINTR); 1499e66f31c5Sopenharmony_ci else if (nfds == 0) 1500e66f31c5Sopenharmony_ci /* Unlimited timeout should only return with events or signal. */ 1501e66f31c5Sopenharmony_ci assert(timeout != -1); 1502e66f31c5Sopenharmony_ci 1503e66f31c5Sopenharmony_ci if (nfds == 0 || nfds == -1) { 1504e66f31c5Sopenharmony_ci if (reset_timeout != 0) { 1505e66f31c5Sopenharmony_ci timeout = user_timeout; 1506e66f31c5Sopenharmony_ci reset_timeout = 0; 1507e66f31c5Sopenharmony_ci } else if (nfds == 0) { 1508e66f31c5Sopenharmony_ci return; 1509e66f31c5Sopenharmony_ci } 1510e66f31c5Sopenharmony_ci 1511e66f31c5Sopenharmony_ci /* Interrupted by a signal. Update timeout and poll again. */ 1512e66f31c5Sopenharmony_ci goto update_timeout; 1513e66f31c5Sopenharmony_ci } 1514e66f31c5Sopenharmony_ci 1515e66f31c5Sopenharmony_ci have_iou_events = 0; 1516e66f31c5Sopenharmony_ci have_signals = 0; 1517e66f31c5Sopenharmony_ci nevents = 0; 1518e66f31c5Sopenharmony_ci 1519e66f31c5Sopenharmony_ci inv.nfds = nfds; 1520e66f31c5Sopenharmony_ci lfields->inv = &inv; 1521e66f31c5Sopenharmony_ci 1522e66f31c5Sopenharmony_ci for (i = 0; i < nfds; i++) { 1523e66f31c5Sopenharmony_ci pe = events + i; 1524e66f31c5Sopenharmony_ci fd = pe->data.fd; 1525e66f31c5Sopenharmony_ci 1526e66f31c5Sopenharmony_ci /* Skip invalidated events, see uv__platform_invalidate_fd */ 1527e66f31c5Sopenharmony_ci if (fd == -1) 1528e66f31c5Sopenharmony_ci continue; 1529e66f31c5Sopenharmony_ci 1530e66f31c5Sopenharmony_ci if (fd == iou->ringfd) { 1531e66f31c5Sopenharmony_ci uv__poll_io_uring(loop, iou); 1532e66f31c5Sopenharmony_ci have_iou_events = 1; 1533e66f31c5Sopenharmony_ci continue; 1534e66f31c5Sopenharmony_ci } 1535e66f31c5Sopenharmony_ci 1536e66f31c5Sopenharmony_ci#ifndef USE_OHOS_DFX 1537e66f31c5Sopenharmony_ci assert(fd >= 0); 1538e66f31c5Sopenharmony_ci assert((unsigned) fd < loop->nwatchers); 1539e66f31c5Sopenharmony_ci#else 1540e66f31c5Sopenharmony_ci if (fd < 0 || (unsigned) fd >= loop->nwatchers) 1541e66f31c5Sopenharmony_ci continue; 1542e66f31c5Sopenharmony_ci#endif 1543e66f31c5Sopenharmony_ci 1544e66f31c5Sopenharmony_ci w = loop->watchers[fd]; 1545e66f31c5Sopenharmony_ci 1546e66f31c5Sopenharmony_ci if (w == NULL) { 1547e66f31c5Sopenharmony_ci /* File descriptor that we've stopped watching, disarm it. 1548e66f31c5Sopenharmony_ci * 1549e66f31c5Sopenharmony_ci * Ignore all errors because we may be racing with another thread 1550e66f31c5Sopenharmony_ci * when the file descriptor is closed. 1551e66f31c5Sopenharmony_ci */ 1552e66f31c5Sopenharmony_ci uv__epoll_ctl_prep(epollfd, ctl, &prep, EPOLL_CTL_DEL, fd, pe); 1553e66f31c5Sopenharmony_ci continue; 1554e66f31c5Sopenharmony_ci } 1555e66f31c5Sopenharmony_ci 1556e66f31c5Sopenharmony_ci /* Give users only events they're interested in. Prevents spurious 1557e66f31c5Sopenharmony_ci * callbacks when previous callback invocation in this loop has stopped 1558e66f31c5Sopenharmony_ci * the current watcher. Also, filters out events that users has not 1559e66f31c5Sopenharmony_ci * requested us to watch. 1560e66f31c5Sopenharmony_ci */ 1561e66f31c5Sopenharmony_ci pe->events &= w->pevents | POLLERR | POLLHUP; 1562e66f31c5Sopenharmony_ci 1563e66f31c5Sopenharmony_ci /* Work around an epoll quirk where it sometimes reports just the 1564e66f31c5Sopenharmony_ci * EPOLLERR or EPOLLHUP event. In order to force the event loop to 1565e66f31c5Sopenharmony_ci * move forward, we merge in the read/write events that the watcher 1566e66f31c5Sopenharmony_ci * is interested in; uv__read() and uv__write() will then deal with 1567e66f31c5Sopenharmony_ci * the error or hangup in the usual fashion. 1568e66f31c5Sopenharmony_ci * 1569e66f31c5Sopenharmony_ci * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user 1570e66f31c5Sopenharmony_ci * reads the available data, calls uv_read_stop(), then sometime later 1571e66f31c5Sopenharmony_ci * calls uv_read_start() again. By then, libuv has forgotten about the 1572e66f31c5Sopenharmony_ci * hangup and the kernel won't report EPOLLIN again because there's 1573e66f31c5Sopenharmony_ci * nothing left to read. If anything, libuv is to blame here. The 1574e66f31c5Sopenharmony_ci * current hack is just a quick bandaid; to properly fix it, libuv 1575e66f31c5Sopenharmony_ci * needs to remember the error/hangup event. We should get that for 1576e66f31c5Sopenharmony_ci * free when we switch over to edge-triggered I/O. 1577e66f31c5Sopenharmony_ci */ 1578e66f31c5Sopenharmony_ci if (pe->events == POLLERR || pe->events == POLLHUP) 1579e66f31c5Sopenharmony_ci pe->events |= 1580e66f31c5Sopenharmony_ci w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); 1581e66f31c5Sopenharmony_ci 1582e66f31c5Sopenharmony_ci if (pe->events != 0) { 1583e66f31c5Sopenharmony_ci /* Run signal watchers last. This also affects child process watchers 1584e66f31c5Sopenharmony_ci * because those are implemented in terms of signal watchers. 1585e66f31c5Sopenharmony_ci */ 1586e66f31c5Sopenharmony_ci if (w == &loop->signal_io_watcher) { 1587e66f31c5Sopenharmony_ci have_signals = 1; 1588e66f31c5Sopenharmony_ci } else { 1589e66f31c5Sopenharmony_ci uv__metrics_update_idle_time(loop); 1590e66f31c5Sopenharmony_ci w->cb(loop, w, pe->events); 1591e66f31c5Sopenharmony_ci } 1592e66f31c5Sopenharmony_ci 1593e66f31c5Sopenharmony_ci nevents++; 1594e66f31c5Sopenharmony_ci } 1595e66f31c5Sopenharmony_ci } 1596e66f31c5Sopenharmony_ci 1597e66f31c5Sopenharmony_ci uv__metrics_inc_events(loop, nevents); 1598e66f31c5Sopenharmony_ci if (reset_timeout != 0) { 1599e66f31c5Sopenharmony_ci timeout = user_timeout; 1600e66f31c5Sopenharmony_ci reset_timeout = 0; 1601e66f31c5Sopenharmony_ci uv__metrics_inc_events_waiting(loop, nevents); 1602e66f31c5Sopenharmony_ci } 1603e66f31c5Sopenharmony_ci 1604e66f31c5Sopenharmony_ci if (have_signals != 0) { 1605e66f31c5Sopenharmony_ci uv__metrics_update_idle_time(loop); 1606e66f31c5Sopenharmony_ci loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); 1607e66f31c5Sopenharmony_ci } 1608e66f31c5Sopenharmony_ci 1609e66f31c5Sopenharmony_ci lfields->inv = NULL; 1610e66f31c5Sopenharmony_ci 1611e66f31c5Sopenharmony_ci if (have_iou_events != 0) 1612e66f31c5Sopenharmony_ci break; /* Event loop should cycle now so don't poll again. */ 1613e66f31c5Sopenharmony_ci 1614e66f31c5Sopenharmony_ci if (have_signals != 0) 1615e66f31c5Sopenharmony_ci break; /* Event loop should cycle now so don't poll again. */ 1616e66f31c5Sopenharmony_ci 1617e66f31c5Sopenharmony_ci if (nevents != 0) { 1618e66f31c5Sopenharmony_ci if (nfds == ARRAY_SIZE(events) && --count != 0) { 1619e66f31c5Sopenharmony_ci /* Poll for more events but don't block this time. */ 1620e66f31c5Sopenharmony_ci timeout = 0; 1621e66f31c5Sopenharmony_ci continue; 1622e66f31c5Sopenharmony_ci } 1623e66f31c5Sopenharmony_ci break; 1624e66f31c5Sopenharmony_ci } 1625e66f31c5Sopenharmony_ci 1626e66f31c5Sopenharmony_ciupdate_timeout: 1627e66f31c5Sopenharmony_ci if (timeout == 0) 1628e66f31c5Sopenharmony_ci break; 1629e66f31c5Sopenharmony_ci 1630e66f31c5Sopenharmony_ci if (timeout == -1) 1631e66f31c5Sopenharmony_ci continue; 1632e66f31c5Sopenharmony_ci 1633e66f31c5Sopenharmony_ci assert(timeout > 0); 1634e66f31c5Sopenharmony_ci 1635e66f31c5Sopenharmony_ci real_timeout -= (loop->time - base); 1636e66f31c5Sopenharmony_ci if (real_timeout <= 0) 1637e66f31c5Sopenharmony_ci break; 1638e66f31c5Sopenharmony_ci 1639e66f31c5Sopenharmony_ci timeout = real_timeout; 1640e66f31c5Sopenharmony_ci } 1641e66f31c5Sopenharmony_ci 1642e66f31c5Sopenharmony_ci if (ctl->ringfd != -1) 1643e66f31c5Sopenharmony_ci while (*ctl->sqhead != *ctl->sqtail) 1644e66f31c5Sopenharmony_ci uv__epoll_ctl_flush(epollfd, ctl, &prep); 1645e66f31c5Sopenharmony_ci} 1646e66f31c5Sopenharmony_ci 1647e66f31c5Sopenharmony_ciuint64_t uv__hrtime(uv_clocktype_t type) { 1648e66f31c5Sopenharmony_ci static _Atomic clock_t fast_clock_id = -1; 1649e66f31c5Sopenharmony_ci struct timespec t; 1650e66f31c5Sopenharmony_ci clock_t clock_id; 1651e66f31c5Sopenharmony_ci 1652e66f31c5Sopenharmony_ci /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has 1653e66f31c5Sopenharmony_ci * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is 1654e66f31c5Sopenharmony_ci * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may 1655e66f31c5Sopenharmony_ci * decide to make a costly system call. 1656e66f31c5Sopenharmony_ci */ 1657e66f31c5Sopenharmony_ci /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE 1658e66f31c5Sopenharmony_ci * when it has microsecond granularity or better (unlikely). 1659e66f31c5Sopenharmony_ci */ 1660e66f31c5Sopenharmony_ci clock_id = CLOCK_MONOTONIC; 1661e66f31c5Sopenharmony_ci if (type != UV_CLOCK_FAST) 1662e66f31c5Sopenharmony_ci goto done; 1663e66f31c5Sopenharmony_ci 1664e66f31c5Sopenharmony_ci clock_id = atomic_load_explicit(&fast_clock_id, memory_order_relaxed); 1665e66f31c5Sopenharmony_ci if (clock_id != -1) 1666e66f31c5Sopenharmony_ci goto done; 1667e66f31c5Sopenharmony_ci 1668e66f31c5Sopenharmony_ci clock_id = CLOCK_MONOTONIC; 1669e66f31c5Sopenharmony_ci if (0 == clock_getres(CLOCK_MONOTONIC_COARSE, &t)) 1670e66f31c5Sopenharmony_ci if (t.tv_nsec <= 1 * 1000 * 1000) 1671e66f31c5Sopenharmony_ci clock_id = CLOCK_MONOTONIC_COARSE; 1672e66f31c5Sopenharmony_ci 1673e66f31c5Sopenharmony_ci atomic_store_explicit(&fast_clock_id, clock_id, memory_order_relaxed); 1674e66f31c5Sopenharmony_ci 1675e66f31c5Sopenharmony_cidone: 1676e66f31c5Sopenharmony_ci 1677e66f31c5Sopenharmony_ci if (clock_gettime(clock_id, &t)) 1678e66f31c5Sopenharmony_ci return 0; /* Not really possible. */ 1679e66f31c5Sopenharmony_ci 1680e66f31c5Sopenharmony_ci return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; 1681e66f31c5Sopenharmony_ci} 1682e66f31c5Sopenharmony_ci 1683e66f31c5Sopenharmony_ci 1684e66f31c5Sopenharmony_ciint uv_resident_set_memory(size_t* rss) { 1685e66f31c5Sopenharmony_ci char buf[1024]; 1686e66f31c5Sopenharmony_ci const char* s; 1687e66f31c5Sopenharmony_ci ssize_t n; 1688e66f31c5Sopenharmony_ci long val; 1689e66f31c5Sopenharmony_ci int fd; 1690e66f31c5Sopenharmony_ci int i; 1691e66f31c5Sopenharmony_ci 1692e66f31c5Sopenharmony_ci do 1693e66f31c5Sopenharmony_ci fd = open("/proc/self/stat", O_RDONLY); 1694e66f31c5Sopenharmony_ci while (fd == -1 && errno == EINTR); 1695e66f31c5Sopenharmony_ci 1696e66f31c5Sopenharmony_ci if (fd == -1) 1697e66f31c5Sopenharmony_ci return UV__ERR(errno); 1698e66f31c5Sopenharmony_ci 1699e66f31c5Sopenharmony_ci do 1700e66f31c5Sopenharmony_ci n = read(fd, buf, sizeof(buf) - 1); 1701e66f31c5Sopenharmony_ci while (n == -1 && errno == EINTR); 1702e66f31c5Sopenharmony_ci 1703e66f31c5Sopenharmony_ci uv__close(fd); 1704e66f31c5Sopenharmony_ci if (n == -1) 1705e66f31c5Sopenharmony_ci return UV__ERR(errno); 1706e66f31c5Sopenharmony_ci buf[n] = '\0'; 1707e66f31c5Sopenharmony_ci 1708e66f31c5Sopenharmony_ci s = strchr(buf, ' '); 1709e66f31c5Sopenharmony_ci if (s == NULL) 1710e66f31c5Sopenharmony_ci goto err; 1711e66f31c5Sopenharmony_ci 1712e66f31c5Sopenharmony_ci s += 1; 1713e66f31c5Sopenharmony_ci if (*s != '(') 1714e66f31c5Sopenharmony_ci goto err; 1715e66f31c5Sopenharmony_ci 1716e66f31c5Sopenharmony_ci s = strchr(s, ')'); 1717e66f31c5Sopenharmony_ci if (s == NULL) 1718e66f31c5Sopenharmony_ci goto err; 1719e66f31c5Sopenharmony_ci 1720e66f31c5Sopenharmony_ci for (i = 1; i <= 22; i++) { 1721e66f31c5Sopenharmony_ci s = strchr(s + 1, ' '); 1722e66f31c5Sopenharmony_ci if (s == NULL) 1723e66f31c5Sopenharmony_ci goto err; 1724e66f31c5Sopenharmony_ci } 1725e66f31c5Sopenharmony_ci 1726e66f31c5Sopenharmony_ci errno = 0; 1727e66f31c5Sopenharmony_ci val = strtol(s, NULL, 10); 1728e66f31c5Sopenharmony_ci if (errno != 0) 1729e66f31c5Sopenharmony_ci goto err; 1730e66f31c5Sopenharmony_ci if (val < 0) 1731e66f31c5Sopenharmony_ci goto err; 1732e66f31c5Sopenharmony_ci 1733e66f31c5Sopenharmony_ci *rss = val * getpagesize(); 1734e66f31c5Sopenharmony_ci return 0; 1735e66f31c5Sopenharmony_ci 1736e66f31c5Sopenharmony_cierr: 1737e66f31c5Sopenharmony_ci return UV_EINVAL; 1738e66f31c5Sopenharmony_ci} 1739e66f31c5Sopenharmony_ci 1740e66f31c5Sopenharmony_ciint uv_uptime(double* uptime) { 1741e66f31c5Sopenharmony_ci struct timespec now; 1742e66f31c5Sopenharmony_ci char buf[128]; 1743e66f31c5Sopenharmony_ci 1744e66f31c5Sopenharmony_ci /* Consult /proc/uptime when present (common case), or fall back to 1745e66f31c5Sopenharmony_ci * clock_gettime. Why not always clock_gettime? It doesn't always return the 1746e66f31c5Sopenharmony_ci * right result under OpenVZ and possibly other containerized environments. 1747e66f31c5Sopenharmony_ci */ 1748e66f31c5Sopenharmony_ci if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf))) 1749e66f31c5Sopenharmony_ci if (1 == sscanf(buf, "%lf", uptime)) 1750e66f31c5Sopenharmony_ci return 0; 1751e66f31c5Sopenharmony_ci 1752e66f31c5Sopenharmony_ci if (clock_gettime(CLOCK_BOOTTIME, &now)) 1753e66f31c5Sopenharmony_ci return UV__ERR(errno); 1754e66f31c5Sopenharmony_ci 1755e66f31c5Sopenharmony_ci *uptime = now.tv_sec; 1756e66f31c5Sopenharmony_ci return 0; 1757e66f31c5Sopenharmony_ci} 1758e66f31c5Sopenharmony_ci 1759e66f31c5Sopenharmony_ci 1760e66f31c5Sopenharmony_ciint uv_cpu_info(uv_cpu_info_t** ci, int* count) { 1761e66f31c5Sopenharmony_ci#if defined(__PPC__) 1762e66f31c5Sopenharmony_ci static const char model_marker[] = "cpu\t\t: "; 1763e66f31c5Sopenharmony_ci#elif defined(__arm__) 1764e66f31c5Sopenharmony_ci static const char model_marker[] = "Processor\t: "; 1765e66f31c5Sopenharmony_ci#elif defined(__aarch64__) 1766e66f31c5Sopenharmony_ci static const char model_marker[] = "CPU part\t: "; 1767e66f31c5Sopenharmony_ci#elif defined(__mips__) 1768e66f31c5Sopenharmony_ci static const char model_marker[] = "cpu model\t\t: "; 1769e66f31c5Sopenharmony_ci#elif defined(__loongarch__) 1770e66f31c5Sopenharmony_ci static const char model_marker[] = "cpu family\t\t: "; 1771e66f31c5Sopenharmony_ci#else 1772e66f31c5Sopenharmony_ci static const char model_marker[] = "model name\t: "; 1773e66f31c5Sopenharmony_ci#endif 1774e66f31c5Sopenharmony_ci static const char parts[] = 1775e66f31c5Sopenharmony_ci#ifdef __aarch64__ 1776e66f31c5Sopenharmony_ci "0x811\nARM810\n" "0x920\nARM920\n" "0x922\nARM922\n" 1777e66f31c5Sopenharmony_ci "0x926\nARM926\n" "0x940\nARM940\n" "0x946\nARM946\n" 1778e66f31c5Sopenharmony_ci "0x966\nARM966\n" "0xa20\nARM1020\n" "0xa22\nARM1022\n" 1779e66f31c5Sopenharmony_ci "0xa26\nARM1026\n" "0xb02\nARM11 MPCore\n" "0xb36\nARM1136\n" 1780e66f31c5Sopenharmony_ci "0xb56\nARM1156\n" "0xb76\nARM1176\n" "0xc05\nCortex-A5\n" 1781e66f31c5Sopenharmony_ci "0xc07\nCortex-A7\n" "0xc08\nCortex-A8\n" "0xc09\nCortex-A9\n" 1782e66f31c5Sopenharmony_ci "0xc0d\nCortex-A17\n" /* Originally A12 */ 1783e66f31c5Sopenharmony_ci "0xc0f\nCortex-A15\n" "0xc0e\nCortex-A17\n" "0xc14\nCortex-R4\n" 1784e66f31c5Sopenharmony_ci "0xc15\nCortex-R5\n" "0xc17\nCortex-R7\n" "0xc18\nCortex-R8\n" 1785e66f31c5Sopenharmony_ci "0xc20\nCortex-M0\n" "0xc21\nCortex-M1\n" "0xc23\nCortex-M3\n" 1786e66f31c5Sopenharmony_ci "0xc24\nCortex-M4\n" "0xc27\nCortex-M7\n" "0xc60\nCortex-M0+\n" 1787e66f31c5Sopenharmony_ci "0xd01\nCortex-A32\n" "0xd03\nCortex-A53\n" "0xd04\nCortex-A35\n" 1788e66f31c5Sopenharmony_ci "0xd05\nCortex-A55\n" "0xd06\nCortex-A65\n" "0xd07\nCortex-A57\n" 1789e66f31c5Sopenharmony_ci "0xd08\nCortex-A72\n" "0xd09\nCortex-A73\n" "0xd0a\nCortex-A75\n" 1790e66f31c5Sopenharmony_ci "0xd0b\nCortex-A76\n" "0xd0c\nNeoverse-N1\n" "0xd0d\nCortex-A77\n" 1791e66f31c5Sopenharmony_ci "0xd0e\nCortex-A76AE\n" "0xd13\nCortex-R52\n" "0xd20\nCortex-M23\n" 1792e66f31c5Sopenharmony_ci "0xd21\nCortex-M33\n" "0xd41\nCortex-A78\n" "0xd42\nCortex-A78AE\n" 1793e66f31c5Sopenharmony_ci "0xd4a\nNeoverse-E1\n" "0xd4b\nCortex-A78C\n" 1794e66f31c5Sopenharmony_ci#endif 1795e66f31c5Sopenharmony_ci ""; 1796e66f31c5Sopenharmony_ci struct cpu { 1797e66f31c5Sopenharmony_ci unsigned long long freq, user, nice, sys, idle, irq; 1798e66f31c5Sopenharmony_ci unsigned model; 1799e66f31c5Sopenharmony_ci }; 1800e66f31c5Sopenharmony_ci FILE* fp; 1801e66f31c5Sopenharmony_ci char* p; 1802e66f31c5Sopenharmony_ci int found; 1803e66f31c5Sopenharmony_ci int n; 1804e66f31c5Sopenharmony_ci unsigned i; 1805e66f31c5Sopenharmony_ci unsigned cpu; 1806e66f31c5Sopenharmony_ci unsigned maxcpu; 1807e66f31c5Sopenharmony_ci unsigned size; 1808e66f31c5Sopenharmony_ci unsigned long long skip; 1809e66f31c5Sopenharmony_ci struct cpu (*cpus)[8192]; /* Kernel maximum. */ 1810e66f31c5Sopenharmony_ci struct cpu* c; 1811e66f31c5Sopenharmony_ci struct cpu t; 1812e66f31c5Sopenharmony_ci char (*model)[64]; 1813e66f31c5Sopenharmony_ci unsigned char bitmap[ARRAY_SIZE(*cpus) / 8]; 1814e66f31c5Sopenharmony_ci /* Assumption: even big.LITTLE systems will have only a handful 1815e66f31c5Sopenharmony_ci * of different CPU models. Most systems will just have one. 1816e66f31c5Sopenharmony_ci */ 1817e66f31c5Sopenharmony_ci char models[8][64]; 1818e66f31c5Sopenharmony_ci char buf[1024]; 1819e66f31c5Sopenharmony_ci 1820e66f31c5Sopenharmony_ci memset(bitmap, 0, sizeof(bitmap)); 1821e66f31c5Sopenharmony_ci memset(models, 0, sizeof(models)); 1822e66f31c5Sopenharmony_ci snprintf(*models, sizeof(*models), "unknown"); 1823e66f31c5Sopenharmony_ci maxcpu = 0; 1824e66f31c5Sopenharmony_ci 1825e66f31c5Sopenharmony_ci cpus = uv__calloc(ARRAY_SIZE(*cpus), sizeof(**cpus)); 1826e66f31c5Sopenharmony_ci if (cpus == NULL) 1827e66f31c5Sopenharmony_ci return UV_ENOMEM; 1828e66f31c5Sopenharmony_ci 1829e66f31c5Sopenharmony_ci fp = uv__open_file("/proc/stat"); 1830e66f31c5Sopenharmony_ci if (fp == NULL) { 1831e66f31c5Sopenharmony_ci uv__free(cpus); 1832e66f31c5Sopenharmony_ci return UV__ERR(errno); 1833e66f31c5Sopenharmony_ci } 1834e66f31c5Sopenharmony_ci 1835e66f31c5Sopenharmony_ci if (NULL == fgets(buf, sizeof(buf), fp)) 1836e66f31c5Sopenharmony_ci abort(); 1837e66f31c5Sopenharmony_ci 1838e66f31c5Sopenharmony_ci for (;;) { 1839e66f31c5Sopenharmony_ci memset(&t, 0, sizeof(t)); 1840e66f31c5Sopenharmony_ci 1841e66f31c5Sopenharmony_ci n = fscanf(fp, "cpu%u %llu %llu %llu %llu %llu %llu", 1842e66f31c5Sopenharmony_ci &cpu, &t.user, &t.nice, &t.sys, &t.idle, &skip, &t.irq); 1843e66f31c5Sopenharmony_ci 1844e66f31c5Sopenharmony_ci if (n != 7) 1845e66f31c5Sopenharmony_ci break; 1846e66f31c5Sopenharmony_ci 1847e66f31c5Sopenharmony_ci if (NULL == fgets(buf, sizeof(buf), fp)) 1848e66f31c5Sopenharmony_ci abort(); 1849e66f31c5Sopenharmony_ci 1850e66f31c5Sopenharmony_ci if (cpu >= ARRAY_SIZE(*cpus)) 1851e66f31c5Sopenharmony_ci continue; 1852e66f31c5Sopenharmony_ci 1853e66f31c5Sopenharmony_ci (*cpus)[cpu] = t; 1854e66f31c5Sopenharmony_ci 1855e66f31c5Sopenharmony_ci bitmap[cpu >> 3] |= 1 << (cpu & 7); 1856e66f31c5Sopenharmony_ci 1857e66f31c5Sopenharmony_ci if (cpu >= maxcpu) 1858e66f31c5Sopenharmony_ci maxcpu = cpu + 1; 1859e66f31c5Sopenharmony_ci } 1860e66f31c5Sopenharmony_ci 1861e66f31c5Sopenharmony_ci fclose(fp); 1862e66f31c5Sopenharmony_ci 1863e66f31c5Sopenharmony_ci fp = uv__open_file("/proc/cpuinfo"); 1864e66f31c5Sopenharmony_ci if (fp == NULL) 1865e66f31c5Sopenharmony_ci goto nocpuinfo; 1866e66f31c5Sopenharmony_ci 1867e66f31c5Sopenharmony_ci for (;;) { 1868e66f31c5Sopenharmony_ci if (1 != fscanf(fp, "processor\t: %u\n", &cpu)) 1869e66f31c5Sopenharmony_ci break; /* Parse error. */ 1870e66f31c5Sopenharmony_ci 1871e66f31c5Sopenharmony_ci found = 0; 1872e66f31c5Sopenharmony_ci while (!found && fgets(buf, sizeof(buf), fp)) 1873e66f31c5Sopenharmony_ci found = !strncmp(buf, model_marker, sizeof(model_marker) - 1); 1874e66f31c5Sopenharmony_ci 1875e66f31c5Sopenharmony_ci if (!found) 1876e66f31c5Sopenharmony_ci goto next; 1877e66f31c5Sopenharmony_ci 1878e66f31c5Sopenharmony_ci p = buf + sizeof(model_marker) - 1; 1879e66f31c5Sopenharmony_ci n = (int) strcspn(p, "\n"); 1880e66f31c5Sopenharmony_ci 1881e66f31c5Sopenharmony_ci /* arm64: translate CPU part code to model name. */ 1882e66f31c5Sopenharmony_ci if (*parts) { 1883e66f31c5Sopenharmony_ci p = memmem(parts, sizeof(parts) - 1, p, n + 1); 1884e66f31c5Sopenharmony_ci if (p == NULL) 1885e66f31c5Sopenharmony_ci p = "unknown"; 1886e66f31c5Sopenharmony_ci else 1887e66f31c5Sopenharmony_ci p += n + 1; 1888e66f31c5Sopenharmony_ci n = (int) strcspn(p, "\n"); 1889e66f31c5Sopenharmony_ci } 1890e66f31c5Sopenharmony_ci 1891e66f31c5Sopenharmony_ci found = 0; 1892e66f31c5Sopenharmony_ci for (model = models; !found && model < ARRAY_END(models); model++) 1893e66f31c5Sopenharmony_ci found = !strncmp(p, *model, strlen(*model)); 1894e66f31c5Sopenharmony_ci 1895e66f31c5Sopenharmony_ci if (!found) 1896e66f31c5Sopenharmony_ci goto next; 1897e66f31c5Sopenharmony_ci 1898e66f31c5Sopenharmony_ci if (**model == '\0') 1899e66f31c5Sopenharmony_ci snprintf(*model, sizeof(*model), "%.*s", n, p); 1900e66f31c5Sopenharmony_ci 1901e66f31c5Sopenharmony_ci if (cpu < maxcpu) 1902e66f31c5Sopenharmony_ci (*cpus)[cpu].model = model - models; 1903e66f31c5Sopenharmony_ci 1904e66f31c5Sopenharmony_cinext: 1905e66f31c5Sopenharmony_ci while (fgets(buf, sizeof(buf), fp)) 1906e66f31c5Sopenharmony_ci if (*buf == '\n') 1907e66f31c5Sopenharmony_ci break; 1908e66f31c5Sopenharmony_ci } 1909e66f31c5Sopenharmony_ci 1910e66f31c5Sopenharmony_ci fclose(fp); 1911e66f31c5Sopenharmony_ci fp = NULL; 1912e66f31c5Sopenharmony_ci 1913e66f31c5Sopenharmony_cinocpuinfo: 1914e66f31c5Sopenharmony_ci 1915e66f31c5Sopenharmony_ci n = 0; 1916e66f31c5Sopenharmony_ci for (cpu = 0; cpu < maxcpu; cpu++) { 1917e66f31c5Sopenharmony_ci if (!(bitmap[cpu >> 3] & (1 << (cpu & 7)))) 1918e66f31c5Sopenharmony_ci continue; 1919e66f31c5Sopenharmony_ci 1920e66f31c5Sopenharmony_ci n++; 1921e66f31c5Sopenharmony_ci snprintf(buf, sizeof(buf), 1922e66f31c5Sopenharmony_ci "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq", cpu); 1923e66f31c5Sopenharmony_ci 1924e66f31c5Sopenharmony_ci fp = uv__open_file(buf); 1925e66f31c5Sopenharmony_ci if (fp == NULL) 1926e66f31c5Sopenharmony_ci continue; 1927e66f31c5Sopenharmony_ci 1928e66f31c5Sopenharmony_ci if (1 != fscanf(fp, "%llu", &(*cpus)[cpu].freq)) 1929e66f31c5Sopenharmony_ci abort(); 1930e66f31c5Sopenharmony_ci fclose(fp); 1931e66f31c5Sopenharmony_ci fp = NULL; 1932e66f31c5Sopenharmony_ci } 1933e66f31c5Sopenharmony_ci 1934e66f31c5Sopenharmony_ci size = n * sizeof(**ci) + sizeof(models); 1935e66f31c5Sopenharmony_ci *ci = uv__malloc(size); 1936e66f31c5Sopenharmony_ci *count = 0; 1937e66f31c5Sopenharmony_ci 1938e66f31c5Sopenharmony_ci if (*ci == NULL) { 1939e66f31c5Sopenharmony_ci uv__free(cpus); 1940e66f31c5Sopenharmony_ci return UV_ENOMEM; 1941e66f31c5Sopenharmony_ci } 1942e66f31c5Sopenharmony_ci 1943e66f31c5Sopenharmony_ci *count = n; 1944e66f31c5Sopenharmony_ci p = memcpy(*ci + n, models, sizeof(models)); 1945e66f31c5Sopenharmony_ci 1946e66f31c5Sopenharmony_ci i = 0; 1947e66f31c5Sopenharmony_ci for (cpu = 0; cpu < maxcpu; cpu++) { 1948e66f31c5Sopenharmony_ci if (!(bitmap[cpu >> 3] & (1 << (cpu & 7)))) 1949e66f31c5Sopenharmony_ci continue; 1950e66f31c5Sopenharmony_ci 1951e66f31c5Sopenharmony_ci c = *cpus + cpu; 1952e66f31c5Sopenharmony_ci 1953e66f31c5Sopenharmony_ci (*ci)[i++] = (uv_cpu_info_t) { 1954e66f31c5Sopenharmony_ci .model = p + c->model * sizeof(*model), 1955e66f31c5Sopenharmony_ci .speed = c->freq / 1000, 1956e66f31c5Sopenharmony_ci /* Note: sysconf(_SC_CLK_TCK) is fixed at 100 Hz, 1957e66f31c5Sopenharmony_ci * therefore the multiplier is always 1000/100 = 10. 1958e66f31c5Sopenharmony_ci */ 1959e66f31c5Sopenharmony_ci .cpu_times = (struct uv_cpu_times_s) { 1960e66f31c5Sopenharmony_ci .user = 10 * c->user, 1961e66f31c5Sopenharmony_ci .nice = 10 * c->nice, 1962e66f31c5Sopenharmony_ci .sys = 10 * c->sys, 1963e66f31c5Sopenharmony_ci .idle = 10 * c->idle, 1964e66f31c5Sopenharmony_ci .irq = 10 * c->irq, 1965e66f31c5Sopenharmony_ci }, 1966e66f31c5Sopenharmony_ci }; 1967e66f31c5Sopenharmony_ci } 1968e66f31c5Sopenharmony_ci 1969e66f31c5Sopenharmony_ci uv__free(cpus); 1970e66f31c5Sopenharmony_ci 1971e66f31c5Sopenharmony_ci return 0; 1972e66f31c5Sopenharmony_ci} 1973e66f31c5Sopenharmony_ci 1974e66f31c5Sopenharmony_ci 1975e66f31c5Sopenharmony_cistatic int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { 1976e66f31c5Sopenharmony_ci if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) 1977e66f31c5Sopenharmony_ci return 1; 1978e66f31c5Sopenharmony_ci if (ent->ifa_addr == NULL) 1979e66f31c5Sopenharmony_ci return 1; 1980e66f31c5Sopenharmony_ci /* 1981e66f31c5Sopenharmony_ci * On Linux getifaddrs returns information related to the raw underlying 1982e66f31c5Sopenharmony_ci * devices. We're not interested in this information yet. 1983e66f31c5Sopenharmony_ci */ 1984e66f31c5Sopenharmony_ci if (ent->ifa_addr->sa_family == PF_PACKET) 1985e66f31c5Sopenharmony_ci return exclude_type; 1986e66f31c5Sopenharmony_ci return !exclude_type; 1987e66f31c5Sopenharmony_ci} 1988e66f31c5Sopenharmony_ci 1989e66f31c5Sopenharmony_ciint uv_interface_addresses(uv_interface_address_t** addresses, int* count) { 1990e66f31c5Sopenharmony_ci struct ifaddrs *addrs, *ent; 1991e66f31c5Sopenharmony_ci uv_interface_address_t* address; 1992e66f31c5Sopenharmony_ci int i; 1993e66f31c5Sopenharmony_ci struct sockaddr_ll *sll; 1994e66f31c5Sopenharmony_ci 1995e66f31c5Sopenharmony_ci *count = 0; 1996e66f31c5Sopenharmony_ci *addresses = NULL; 1997e66f31c5Sopenharmony_ci 1998e66f31c5Sopenharmony_ci if (getifaddrs(&addrs)) 1999e66f31c5Sopenharmony_ci return UV__ERR(errno); 2000e66f31c5Sopenharmony_ci 2001e66f31c5Sopenharmony_ci /* Count the number of interfaces */ 2002e66f31c5Sopenharmony_ci for (ent = addrs; ent != NULL; ent = ent->ifa_next) { 2003e66f31c5Sopenharmony_ci if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) 2004e66f31c5Sopenharmony_ci continue; 2005e66f31c5Sopenharmony_ci 2006e66f31c5Sopenharmony_ci (*count)++; 2007e66f31c5Sopenharmony_ci } 2008e66f31c5Sopenharmony_ci 2009e66f31c5Sopenharmony_ci if (*count == 0) { 2010e66f31c5Sopenharmony_ci freeifaddrs(addrs); 2011e66f31c5Sopenharmony_ci return 0; 2012e66f31c5Sopenharmony_ci } 2013e66f31c5Sopenharmony_ci 2014e66f31c5Sopenharmony_ci /* Make sure the memory is initiallized to zero using calloc() */ 2015e66f31c5Sopenharmony_ci *addresses = uv__calloc(*count, sizeof(**addresses)); 2016e66f31c5Sopenharmony_ci if (!(*addresses)) { 2017e66f31c5Sopenharmony_ci freeifaddrs(addrs); 2018e66f31c5Sopenharmony_ci return UV_ENOMEM; 2019e66f31c5Sopenharmony_ci } 2020e66f31c5Sopenharmony_ci 2021e66f31c5Sopenharmony_ci address = *addresses; 2022e66f31c5Sopenharmony_ci 2023e66f31c5Sopenharmony_ci for (ent = addrs; ent != NULL; ent = ent->ifa_next) { 2024e66f31c5Sopenharmony_ci if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) 2025e66f31c5Sopenharmony_ci continue; 2026e66f31c5Sopenharmony_ci 2027e66f31c5Sopenharmony_ci address->name = uv__strdup(ent->ifa_name); 2028e66f31c5Sopenharmony_ci 2029e66f31c5Sopenharmony_ci if (ent->ifa_addr->sa_family == AF_INET6) { 2030e66f31c5Sopenharmony_ci address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr); 2031e66f31c5Sopenharmony_ci } else { 2032e66f31c5Sopenharmony_ci address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr); 2033e66f31c5Sopenharmony_ci } 2034e66f31c5Sopenharmony_ci 2035e66f31c5Sopenharmony_ci if (ent->ifa_netmask->sa_family == AF_INET6) { 2036e66f31c5Sopenharmony_ci address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask); 2037e66f31c5Sopenharmony_ci } else { 2038e66f31c5Sopenharmony_ci address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask); 2039e66f31c5Sopenharmony_ci } 2040e66f31c5Sopenharmony_ci 2041e66f31c5Sopenharmony_ci address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK); 2042e66f31c5Sopenharmony_ci 2043e66f31c5Sopenharmony_ci address++; 2044e66f31c5Sopenharmony_ci } 2045e66f31c5Sopenharmony_ci 2046e66f31c5Sopenharmony_ci /* Fill in physical addresses for each interface */ 2047e66f31c5Sopenharmony_ci for (ent = addrs; ent != NULL; ent = ent->ifa_next) { 2048e66f31c5Sopenharmony_ci if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) 2049e66f31c5Sopenharmony_ci continue; 2050e66f31c5Sopenharmony_ci 2051e66f31c5Sopenharmony_ci address = *addresses; 2052e66f31c5Sopenharmony_ci 2053e66f31c5Sopenharmony_ci for (i = 0; i < (*count); i++) { 2054e66f31c5Sopenharmony_ci size_t namelen = strlen(ent->ifa_name); 2055e66f31c5Sopenharmony_ci /* Alias interface share the same physical address */ 2056e66f31c5Sopenharmony_ci if (strncmp(address->name, ent->ifa_name, namelen) == 0 && 2057e66f31c5Sopenharmony_ci (address->name[namelen] == 0 || address->name[namelen] == ':')) { 2058e66f31c5Sopenharmony_ci sll = (struct sockaddr_ll*)ent->ifa_addr; 2059e66f31c5Sopenharmony_ci memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); 2060e66f31c5Sopenharmony_ci } 2061e66f31c5Sopenharmony_ci address++; 2062e66f31c5Sopenharmony_ci } 2063e66f31c5Sopenharmony_ci } 2064e66f31c5Sopenharmony_ci 2065e66f31c5Sopenharmony_ci freeifaddrs(addrs); 2066e66f31c5Sopenharmony_ci 2067e66f31c5Sopenharmony_ci return 0; 2068e66f31c5Sopenharmony_ci} 2069e66f31c5Sopenharmony_ci 2070e66f31c5Sopenharmony_ci 2071e66f31c5Sopenharmony_civoid uv_free_interface_addresses(uv_interface_address_t* addresses, 2072e66f31c5Sopenharmony_ci int count) { 2073e66f31c5Sopenharmony_ci int i; 2074e66f31c5Sopenharmony_ci 2075e66f31c5Sopenharmony_ci for (i = 0; i < count; i++) { 2076e66f31c5Sopenharmony_ci uv__free(addresses[i].name); 2077e66f31c5Sopenharmony_ci } 2078e66f31c5Sopenharmony_ci 2079e66f31c5Sopenharmony_ci uv__free(addresses); 2080e66f31c5Sopenharmony_ci} 2081e66f31c5Sopenharmony_ci 2082e66f31c5Sopenharmony_ci 2083e66f31c5Sopenharmony_civoid uv__set_process_title(const char* title) { 2084e66f31c5Sopenharmony_ci#if defined(PR_SET_NAME) 2085e66f31c5Sopenharmony_ci prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */ 2086e66f31c5Sopenharmony_ci#endif 2087e66f31c5Sopenharmony_ci} 2088e66f31c5Sopenharmony_ci 2089e66f31c5Sopenharmony_ci 2090e66f31c5Sopenharmony_cistatic uint64_t uv__read_proc_meminfo(const char* what) { 2091e66f31c5Sopenharmony_ci uint64_t rc; 2092e66f31c5Sopenharmony_ci char* p; 2093e66f31c5Sopenharmony_ci char buf[4096]; /* Large enough to hold all of /proc/meminfo. */ 2094e66f31c5Sopenharmony_ci 2095e66f31c5Sopenharmony_ci if (uv__slurp("/proc/meminfo", buf, sizeof(buf))) 2096e66f31c5Sopenharmony_ci return 0; 2097e66f31c5Sopenharmony_ci 2098e66f31c5Sopenharmony_ci p = strstr(buf, what); 2099e66f31c5Sopenharmony_ci 2100e66f31c5Sopenharmony_ci if (p == NULL) 2101e66f31c5Sopenharmony_ci return 0; 2102e66f31c5Sopenharmony_ci 2103e66f31c5Sopenharmony_ci p += strlen(what); 2104e66f31c5Sopenharmony_ci 2105e66f31c5Sopenharmony_ci rc = 0; 2106e66f31c5Sopenharmony_ci sscanf(p, "%" PRIu64 " kB", &rc); 2107e66f31c5Sopenharmony_ci 2108e66f31c5Sopenharmony_ci return rc * 1024; 2109e66f31c5Sopenharmony_ci} 2110e66f31c5Sopenharmony_ci 2111e66f31c5Sopenharmony_ci 2112e66f31c5Sopenharmony_ciuint64_t uv_get_free_memory(void) { 2113e66f31c5Sopenharmony_ci struct sysinfo info; 2114e66f31c5Sopenharmony_ci uint64_t rc; 2115e66f31c5Sopenharmony_ci 2116e66f31c5Sopenharmony_ci rc = uv__read_proc_meminfo("MemAvailable:"); 2117e66f31c5Sopenharmony_ci 2118e66f31c5Sopenharmony_ci if (rc != 0) 2119e66f31c5Sopenharmony_ci return rc; 2120e66f31c5Sopenharmony_ci 2121e66f31c5Sopenharmony_ci if (0 == sysinfo(&info)) 2122e66f31c5Sopenharmony_ci return (uint64_t) info.freeram * info.mem_unit; 2123e66f31c5Sopenharmony_ci 2124e66f31c5Sopenharmony_ci return 0; 2125e66f31c5Sopenharmony_ci} 2126e66f31c5Sopenharmony_ci 2127e66f31c5Sopenharmony_ci 2128e66f31c5Sopenharmony_ciuint64_t uv_get_total_memory(void) { 2129e66f31c5Sopenharmony_ci struct sysinfo info; 2130e66f31c5Sopenharmony_ci uint64_t rc; 2131e66f31c5Sopenharmony_ci 2132e66f31c5Sopenharmony_ci rc = uv__read_proc_meminfo("MemTotal:"); 2133e66f31c5Sopenharmony_ci 2134e66f31c5Sopenharmony_ci if (rc != 0) 2135e66f31c5Sopenharmony_ci return rc; 2136e66f31c5Sopenharmony_ci 2137e66f31c5Sopenharmony_ci if (0 == sysinfo(&info)) 2138e66f31c5Sopenharmony_ci return (uint64_t) info.totalram * info.mem_unit; 2139e66f31c5Sopenharmony_ci 2140e66f31c5Sopenharmony_ci return 0; 2141e66f31c5Sopenharmony_ci} 2142e66f31c5Sopenharmony_ci 2143e66f31c5Sopenharmony_ci 2144e66f31c5Sopenharmony_cistatic uint64_t uv__read_uint64(const char* filename) { 2145e66f31c5Sopenharmony_ci char buf[32]; /* Large enough to hold an encoded uint64_t. */ 2146e66f31c5Sopenharmony_ci uint64_t rc; 2147e66f31c5Sopenharmony_ci 2148e66f31c5Sopenharmony_ci rc = 0; 2149e66f31c5Sopenharmony_ci if (0 == uv__slurp(filename, buf, sizeof(buf))) 2150e66f31c5Sopenharmony_ci if (1 != sscanf(buf, "%" PRIu64, &rc)) 2151e66f31c5Sopenharmony_ci if (0 == strcmp(buf, "max\n")) 2152e66f31c5Sopenharmony_ci rc = UINT64_MAX; 2153e66f31c5Sopenharmony_ci 2154e66f31c5Sopenharmony_ci return rc; 2155e66f31c5Sopenharmony_ci} 2156e66f31c5Sopenharmony_ci 2157e66f31c5Sopenharmony_ci 2158e66f31c5Sopenharmony_ci/* Given a buffer with the contents of a cgroup1 /proc/self/cgroups, 2159e66f31c5Sopenharmony_ci * finds the location and length of the memory controller mount path. 2160e66f31c5Sopenharmony_ci * This disregards the leading / for easy concatenation of paths. 2161e66f31c5Sopenharmony_ci * Returns NULL if the memory controller wasn't found. */ 2162e66f31c5Sopenharmony_cistatic char* uv__cgroup1_find_memory_controller(char buf[static 1024], 2163e66f31c5Sopenharmony_ci int* n) { 2164e66f31c5Sopenharmony_ci char* p; 2165e66f31c5Sopenharmony_ci 2166e66f31c5Sopenharmony_ci /* Seek to the memory controller line. */ 2167e66f31c5Sopenharmony_ci p = strchr(buf, ':'); 2168e66f31c5Sopenharmony_ci while (p != NULL && strncmp(p, ":memory:", 8)) { 2169e66f31c5Sopenharmony_ci p = strchr(p, '\n'); 2170e66f31c5Sopenharmony_ci if (p != NULL) 2171e66f31c5Sopenharmony_ci p = strchr(p, ':'); 2172e66f31c5Sopenharmony_ci } 2173e66f31c5Sopenharmony_ci 2174e66f31c5Sopenharmony_ci if (p != NULL) { 2175e66f31c5Sopenharmony_ci /* Determine the length of the mount path. */ 2176e66f31c5Sopenharmony_ci p = p + strlen(":memory:/"); 2177e66f31c5Sopenharmony_ci *n = (int) strcspn(p, "\n"); 2178e66f31c5Sopenharmony_ci } 2179e66f31c5Sopenharmony_ci 2180e66f31c5Sopenharmony_ci return p; 2181e66f31c5Sopenharmony_ci} 2182e66f31c5Sopenharmony_ci 2183e66f31c5Sopenharmony_cistatic void uv__get_cgroup1_memory_limits(char buf[static 1024], uint64_t* high, 2184e66f31c5Sopenharmony_ci uint64_t* max) { 2185e66f31c5Sopenharmony_ci char filename[4097]; 2186e66f31c5Sopenharmony_ci char* p; 2187e66f31c5Sopenharmony_ci int n; 2188e66f31c5Sopenharmony_ci uint64_t cgroup1_max; 2189e66f31c5Sopenharmony_ci 2190e66f31c5Sopenharmony_ci /* Find out where the controller is mounted. */ 2191e66f31c5Sopenharmony_ci p = uv__cgroup1_find_memory_controller(buf, &n); 2192e66f31c5Sopenharmony_ci if (p != NULL) { 2193e66f31c5Sopenharmony_ci snprintf(filename, sizeof(filename), 2194e66f31c5Sopenharmony_ci "/sys/fs/cgroup/memory/%.*s/memory.soft_limit_in_bytes", n, p); 2195e66f31c5Sopenharmony_ci *high = uv__read_uint64(filename); 2196e66f31c5Sopenharmony_ci 2197e66f31c5Sopenharmony_ci snprintf(filename, sizeof(filename), 2198e66f31c5Sopenharmony_ci "/sys/fs/cgroup/memory/%.*s/memory.limit_in_bytes", n, p); 2199e66f31c5Sopenharmony_ci *max = uv__read_uint64(filename); 2200e66f31c5Sopenharmony_ci 2201e66f31c5Sopenharmony_ci /* If the controller wasn't mounted, the reads above will have failed, 2202e66f31c5Sopenharmony_ci * as indicated by uv__read_uint64 returning 0. 2203e66f31c5Sopenharmony_ci */ 2204e66f31c5Sopenharmony_ci if (*high != 0 && *max != 0) 2205e66f31c5Sopenharmony_ci goto update_limits; 2206e66f31c5Sopenharmony_ci } 2207e66f31c5Sopenharmony_ci 2208e66f31c5Sopenharmony_ci /* Fall back to the limits of the global memory controller. */ 2209e66f31c5Sopenharmony_ci *high = uv__read_uint64("/sys/fs/cgroup/memory/memory.soft_limit_in_bytes"); 2210e66f31c5Sopenharmony_ci *max = uv__read_uint64("/sys/fs/cgroup/memory/memory.limit_in_bytes"); 2211e66f31c5Sopenharmony_ci 2212e66f31c5Sopenharmony_ci /* uv__read_uint64 detects cgroup2's "max", so we need to separately detect 2213e66f31c5Sopenharmony_ci * cgroup1's maximum value (which is derived from LONG_MAX and PAGE_SIZE). 2214e66f31c5Sopenharmony_ci */ 2215e66f31c5Sopenharmony_ciupdate_limits: 2216e66f31c5Sopenharmony_ci cgroup1_max = LONG_MAX & ~(sysconf(_SC_PAGESIZE) - 1); 2217e66f31c5Sopenharmony_ci if (*high == cgroup1_max) 2218e66f31c5Sopenharmony_ci *high = UINT64_MAX; 2219e66f31c5Sopenharmony_ci if (*max == cgroup1_max) 2220e66f31c5Sopenharmony_ci *max = UINT64_MAX; 2221e66f31c5Sopenharmony_ci} 2222e66f31c5Sopenharmony_ci 2223e66f31c5Sopenharmony_cistatic void uv__get_cgroup2_memory_limits(char buf[static 1024], uint64_t* high, 2224e66f31c5Sopenharmony_ci uint64_t* max) { 2225e66f31c5Sopenharmony_ci char filename[4097]; 2226e66f31c5Sopenharmony_ci char* p; 2227e66f31c5Sopenharmony_ci int n; 2228e66f31c5Sopenharmony_ci 2229e66f31c5Sopenharmony_ci /* Find out where the controller is mounted. */ 2230e66f31c5Sopenharmony_ci p = buf + strlen("0::/"); 2231e66f31c5Sopenharmony_ci n = (int) strcspn(p, "\n"); 2232e66f31c5Sopenharmony_ci 2233e66f31c5Sopenharmony_ci /* Read the memory limits of the controller. */ 2234e66f31c5Sopenharmony_ci snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%.*s/memory.max", n, p); 2235e66f31c5Sopenharmony_ci *max = uv__read_uint64(filename); 2236e66f31c5Sopenharmony_ci snprintf(filename, sizeof(filename), "/sys/fs/cgroup/%.*s/memory.high", n, p); 2237e66f31c5Sopenharmony_ci *high = uv__read_uint64(filename); 2238e66f31c5Sopenharmony_ci} 2239e66f31c5Sopenharmony_ci 2240e66f31c5Sopenharmony_cistatic uint64_t uv__get_cgroup_constrained_memory(char buf[static 1024]) { 2241e66f31c5Sopenharmony_ci uint64_t high; 2242e66f31c5Sopenharmony_ci uint64_t max; 2243e66f31c5Sopenharmony_ci 2244e66f31c5Sopenharmony_ci /* In the case of cgroupv2, we'll only have a single entry. */ 2245e66f31c5Sopenharmony_ci if (strncmp(buf, "0::/", 4)) 2246e66f31c5Sopenharmony_ci uv__get_cgroup1_memory_limits(buf, &high, &max); 2247e66f31c5Sopenharmony_ci else 2248e66f31c5Sopenharmony_ci uv__get_cgroup2_memory_limits(buf, &high, &max); 2249e66f31c5Sopenharmony_ci 2250e66f31c5Sopenharmony_ci if (high == 0 || max == 0) 2251e66f31c5Sopenharmony_ci return 0; 2252e66f31c5Sopenharmony_ci 2253e66f31c5Sopenharmony_ci return high < max ? high : max; 2254e66f31c5Sopenharmony_ci} 2255e66f31c5Sopenharmony_ci 2256e66f31c5Sopenharmony_ciuint64_t uv_get_constrained_memory(void) { 2257e66f31c5Sopenharmony_ci char buf[1024]; 2258e66f31c5Sopenharmony_ci 2259e66f31c5Sopenharmony_ci if (uv__slurp("/proc/self/cgroup", buf, sizeof(buf))) 2260e66f31c5Sopenharmony_ci return 0; 2261e66f31c5Sopenharmony_ci 2262e66f31c5Sopenharmony_ci return uv__get_cgroup_constrained_memory(buf); 2263e66f31c5Sopenharmony_ci} 2264e66f31c5Sopenharmony_ci 2265e66f31c5Sopenharmony_ci 2266e66f31c5Sopenharmony_cistatic uint64_t uv__get_cgroup1_current_memory(char buf[static 1024]) { 2267e66f31c5Sopenharmony_ci char filename[4097]; 2268e66f31c5Sopenharmony_ci uint64_t current; 2269e66f31c5Sopenharmony_ci char* p; 2270e66f31c5Sopenharmony_ci int n; 2271e66f31c5Sopenharmony_ci 2272e66f31c5Sopenharmony_ci /* Find out where the controller is mounted. */ 2273e66f31c5Sopenharmony_ci p = uv__cgroup1_find_memory_controller(buf, &n); 2274e66f31c5Sopenharmony_ci if (p != NULL) { 2275e66f31c5Sopenharmony_ci snprintf(filename, sizeof(filename), 2276e66f31c5Sopenharmony_ci "/sys/fs/cgroup/memory/%.*s/memory.usage_in_bytes", n, p); 2277e66f31c5Sopenharmony_ci current = uv__read_uint64(filename); 2278e66f31c5Sopenharmony_ci 2279e66f31c5Sopenharmony_ci /* If the controller wasn't mounted, the reads above will have failed, 2280e66f31c5Sopenharmony_ci * as indicated by uv__read_uint64 returning 0. 2281e66f31c5Sopenharmony_ci */ 2282e66f31c5Sopenharmony_ci if (current != 0) 2283e66f31c5Sopenharmony_ci return current; 2284e66f31c5Sopenharmony_ci } 2285e66f31c5Sopenharmony_ci 2286e66f31c5Sopenharmony_ci /* Fall back to the usage of the global memory controller. */ 2287e66f31c5Sopenharmony_ci return uv__read_uint64("/sys/fs/cgroup/memory/memory.usage_in_bytes"); 2288e66f31c5Sopenharmony_ci} 2289e66f31c5Sopenharmony_ci 2290e66f31c5Sopenharmony_cistatic uint64_t uv__get_cgroup2_current_memory(char buf[static 1024]) { 2291e66f31c5Sopenharmony_ci char filename[4097]; 2292e66f31c5Sopenharmony_ci char* p; 2293e66f31c5Sopenharmony_ci int n; 2294e66f31c5Sopenharmony_ci 2295e66f31c5Sopenharmony_ci /* Find out where the controller is mounted. */ 2296e66f31c5Sopenharmony_ci p = buf + strlen("0::/"); 2297e66f31c5Sopenharmony_ci n = (int) strcspn(p, "\n"); 2298e66f31c5Sopenharmony_ci 2299e66f31c5Sopenharmony_ci snprintf(filename, sizeof(filename), 2300e66f31c5Sopenharmony_ci "/sys/fs/cgroup/%.*s/memory.current", n, p); 2301e66f31c5Sopenharmony_ci return uv__read_uint64(filename); 2302e66f31c5Sopenharmony_ci} 2303e66f31c5Sopenharmony_ci 2304e66f31c5Sopenharmony_ciuint64_t uv_get_available_memory(void) { 2305e66f31c5Sopenharmony_ci char buf[1024]; 2306e66f31c5Sopenharmony_ci uint64_t constrained; 2307e66f31c5Sopenharmony_ci uint64_t current; 2308e66f31c5Sopenharmony_ci uint64_t total; 2309e66f31c5Sopenharmony_ci 2310e66f31c5Sopenharmony_ci if (uv__slurp("/proc/self/cgroup", buf, sizeof(buf))) 2311e66f31c5Sopenharmony_ci return 0; 2312e66f31c5Sopenharmony_ci 2313e66f31c5Sopenharmony_ci constrained = uv__get_cgroup_constrained_memory(buf); 2314e66f31c5Sopenharmony_ci if (constrained == 0) 2315e66f31c5Sopenharmony_ci return uv_get_free_memory(); 2316e66f31c5Sopenharmony_ci 2317e66f31c5Sopenharmony_ci total = uv_get_total_memory(); 2318e66f31c5Sopenharmony_ci if (constrained > total) 2319e66f31c5Sopenharmony_ci return uv_get_free_memory(); 2320e66f31c5Sopenharmony_ci 2321e66f31c5Sopenharmony_ci /* In the case of cgroupv2, we'll only have a single entry. */ 2322e66f31c5Sopenharmony_ci if (strncmp(buf, "0::/", 4)) 2323e66f31c5Sopenharmony_ci current = uv__get_cgroup1_current_memory(buf); 2324e66f31c5Sopenharmony_ci else 2325e66f31c5Sopenharmony_ci current = uv__get_cgroup2_current_memory(buf); 2326e66f31c5Sopenharmony_ci 2327e66f31c5Sopenharmony_ci /* memory usage can be higher than the limit (for short bursts of time) */ 2328e66f31c5Sopenharmony_ci if (constrained < current) 2329e66f31c5Sopenharmony_ci return 0; 2330e66f31c5Sopenharmony_ci 2331e66f31c5Sopenharmony_ci return constrained - current; 2332e66f31c5Sopenharmony_ci} 2333e66f31c5Sopenharmony_ci 2334e66f31c5Sopenharmony_ci 2335e66f31c5Sopenharmony_civoid uv_loadavg(double avg[3]) { 2336e66f31c5Sopenharmony_ci struct sysinfo info; 2337e66f31c5Sopenharmony_ci char buf[128]; /* Large enough to hold all of /proc/loadavg. */ 2338e66f31c5Sopenharmony_ci 2339e66f31c5Sopenharmony_ci if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf))) 2340e66f31c5Sopenharmony_ci if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2])) 2341e66f31c5Sopenharmony_ci return; 2342e66f31c5Sopenharmony_ci 2343e66f31c5Sopenharmony_ci if (sysinfo(&info) < 0) 2344e66f31c5Sopenharmony_ci return; 2345e66f31c5Sopenharmony_ci 2346e66f31c5Sopenharmony_ci avg[0] = (double) info.loads[0] / 65536.0; 2347e66f31c5Sopenharmony_ci avg[1] = (double) info.loads[1] / 65536.0; 2348e66f31c5Sopenharmony_ci avg[2] = (double) info.loads[2] / 65536.0; 2349e66f31c5Sopenharmony_ci} 2350e66f31c5Sopenharmony_ci 2351e66f31c5Sopenharmony_ci 2352e66f31c5Sopenharmony_cistatic int compare_watchers(const struct watcher_list* a, 2353e66f31c5Sopenharmony_ci const struct watcher_list* b) { 2354e66f31c5Sopenharmony_ci if (a->wd < b->wd) return -1; 2355e66f31c5Sopenharmony_ci if (a->wd > b->wd) return 1; 2356e66f31c5Sopenharmony_ci return 0; 2357e66f31c5Sopenharmony_ci} 2358e66f31c5Sopenharmony_ci 2359e66f31c5Sopenharmony_ci 2360e66f31c5Sopenharmony_cistatic int init_inotify(uv_loop_t* loop) { 2361e66f31c5Sopenharmony_ci int fd; 2362e66f31c5Sopenharmony_ci 2363e66f31c5Sopenharmony_ci if (loop->inotify_fd != -1) 2364e66f31c5Sopenharmony_ci return 0; 2365e66f31c5Sopenharmony_ci 2366e66f31c5Sopenharmony_ci fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); 2367e66f31c5Sopenharmony_ci if (fd < 0) 2368e66f31c5Sopenharmony_ci return UV__ERR(errno); 2369e66f31c5Sopenharmony_ci 2370e66f31c5Sopenharmony_ci loop->inotify_fd = fd; 2371e66f31c5Sopenharmony_ci uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); 2372e66f31c5Sopenharmony_ci uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); 2373e66f31c5Sopenharmony_ci 2374e66f31c5Sopenharmony_ci return 0; 2375e66f31c5Sopenharmony_ci} 2376e66f31c5Sopenharmony_ci 2377e66f31c5Sopenharmony_ci 2378e66f31c5Sopenharmony_cistatic int uv__inotify_fork(uv_loop_t* loop, struct watcher_list* root) { 2379e66f31c5Sopenharmony_ci /* Open the inotify_fd, and re-arm all the inotify watchers. */ 2380e66f31c5Sopenharmony_ci int err; 2381e66f31c5Sopenharmony_ci struct watcher_list* tmp_watcher_list_iter; 2382e66f31c5Sopenharmony_ci struct watcher_list* watcher_list; 2383e66f31c5Sopenharmony_ci struct watcher_list tmp_watcher_list; 2384e66f31c5Sopenharmony_ci struct uv__queue queue; 2385e66f31c5Sopenharmony_ci struct uv__queue* q; 2386e66f31c5Sopenharmony_ci uv_fs_event_t* handle; 2387e66f31c5Sopenharmony_ci char* tmp_path; 2388e66f31c5Sopenharmony_ci 2389e66f31c5Sopenharmony_ci if (root == NULL) 2390e66f31c5Sopenharmony_ci return 0; 2391e66f31c5Sopenharmony_ci 2392e66f31c5Sopenharmony_ci /* We must restore the old watcher list to be able to close items 2393e66f31c5Sopenharmony_ci * out of it. 2394e66f31c5Sopenharmony_ci */ 2395e66f31c5Sopenharmony_ci loop->inotify_watchers = root; 2396e66f31c5Sopenharmony_ci 2397e66f31c5Sopenharmony_ci uv__queue_init(&tmp_watcher_list.watchers); 2398e66f31c5Sopenharmony_ci /* Note that the queue we use is shared with the start and stop() 2399e66f31c5Sopenharmony_ci * functions, making uv__queue_foreach unsafe to use. So we use the 2400e66f31c5Sopenharmony_ci * uv__queue_move trick to safely iterate. Also don't free the watcher 2401e66f31c5Sopenharmony_ci * list until we're done iterating. c.f. uv__inotify_read. 2402e66f31c5Sopenharmony_ci */ 2403e66f31c5Sopenharmony_ci RB_FOREACH_SAFE(watcher_list, watcher_root, 2404e66f31c5Sopenharmony_ci uv__inotify_watchers(loop), tmp_watcher_list_iter) { 2405e66f31c5Sopenharmony_ci watcher_list->iterating = 1; 2406e66f31c5Sopenharmony_ci uv__queue_move(&watcher_list->watchers, &queue); 2407e66f31c5Sopenharmony_ci while (!uv__queue_empty(&queue)) { 2408e66f31c5Sopenharmony_ci q = uv__queue_head(&queue); 2409e66f31c5Sopenharmony_ci handle = uv__queue_data(q, uv_fs_event_t, watchers); 2410e66f31c5Sopenharmony_ci /* It's critical to keep a copy of path here, because it 2411e66f31c5Sopenharmony_ci * will be set to NULL by stop() and then deallocated by 2412e66f31c5Sopenharmony_ci * maybe_free_watcher_list 2413e66f31c5Sopenharmony_ci */ 2414e66f31c5Sopenharmony_ci tmp_path = uv__strdup(handle->path); 2415e66f31c5Sopenharmony_ci assert(tmp_path != NULL); 2416e66f31c5Sopenharmony_ci uv__queue_remove(q); 2417e66f31c5Sopenharmony_ci uv__queue_insert_tail(&watcher_list->watchers, q); 2418e66f31c5Sopenharmony_ci uv_fs_event_stop(handle); 2419e66f31c5Sopenharmony_ci 2420e66f31c5Sopenharmony_ci uv__queue_insert_tail(&tmp_watcher_list.watchers, &handle->watchers); 2421e66f31c5Sopenharmony_ci handle->path = tmp_path; 2422e66f31c5Sopenharmony_ci } 2423e66f31c5Sopenharmony_ci watcher_list->iterating = 0; 2424e66f31c5Sopenharmony_ci maybe_free_watcher_list(watcher_list, loop); 2425e66f31c5Sopenharmony_ci } 2426e66f31c5Sopenharmony_ci 2427e66f31c5Sopenharmony_ci uv__queue_move(&tmp_watcher_list.watchers, &queue); 2428e66f31c5Sopenharmony_ci while (!uv__queue_empty(&queue)) { 2429e66f31c5Sopenharmony_ci q = uv__queue_head(&queue); 2430e66f31c5Sopenharmony_ci uv__queue_remove(q); 2431e66f31c5Sopenharmony_ci handle = uv__queue_data(q, uv_fs_event_t, watchers); 2432e66f31c5Sopenharmony_ci tmp_path = handle->path; 2433e66f31c5Sopenharmony_ci handle->path = NULL; 2434e66f31c5Sopenharmony_ci err = uv_fs_event_start(handle, handle->cb, tmp_path, 0); 2435e66f31c5Sopenharmony_ci uv__free(tmp_path); 2436e66f31c5Sopenharmony_ci if (err) 2437e66f31c5Sopenharmony_ci return err; 2438e66f31c5Sopenharmony_ci } 2439e66f31c5Sopenharmony_ci 2440e66f31c5Sopenharmony_ci return 0; 2441e66f31c5Sopenharmony_ci} 2442e66f31c5Sopenharmony_ci 2443e66f31c5Sopenharmony_ci 2444e66f31c5Sopenharmony_cistatic struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { 2445e66f31c5Sopenharmony_ci struct watcher_list w; 2446e66f31c5Sopenharmony_ci w.wd = wd; 2447e66f31c5Sopenharmony_ci return RB_FIND(watcher_root, uv__inotify_watchers(loop), &w); 2448e66f31c5Sopenharmony_ci} 2449e66f31c5Sopenharmony_ci 2450e66f31c5Sopenharmony_ci 2451e66f31c5Sopenharmony_cistatic void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { 2452e66f31c5Sopenharmony_ci /* if the watcher_list->watchers is being iterated over, we can't free it. */ 2453e66f31c5Sopenharmony_ci if ((!w->iterating) && uv__queue_empty(&w->watchers)) { 2454e66f31c5Sopenharmony_ci /* No watchers left for this path. Clean up. */ 2455e66f31c5Sopenharmony_ci RB_REMOVE(watcher_root, uv__inotify_watchers(loop), w); 2456e66f31c5Sopenharmony_ci inotify_rm_watch(loop->inotify_fd, w->wd); 2457e66f31c5Sopenharmony_ci uv__free(w); 2458e66f31c5Sopenharmony_ci } 2459e66f31c5Sopenharmony_ci} 2460e66f31c5Sopenharmony_ci 2461e66f31c5Sopenharmony_ci 2462e66f31c5Sopenharmony_cistatic void uv__inotify_read(uv_loop_t* loop, 2463e66f31c5Sopenharmony_ci uv__io_t* dummy, 2464e66f31c5Sopenharmony_ci unsigned int events) { 2465e66f31c5Sopenharmony_ci const struct inotify_event* e; 2466e66f31c5Sopenharmony_ci struct watcher_list* w; 2467e66f31c5Sopenharmony_ci uv_fs_event_t* h; 2468e66f31c5Sopenharmony_ci struct uv__queue queue; 2469e66f31c5Sopenharmony_ci struct uv__queue* q; 2470e66f31c5Sopenharmony_ci const char* path; 2471e66f31c5Sopenharmony_ci ssize_t size; 2472e66f31c5Sopenharmony_ci const char *p; 2473e66f31c5Sopenharmony_ci /* needs to be large enough for sizeof(inotify_event) + strlen(path) */ 2474e66f31c5Sopenharmony_ci char buf[4096]; 2475e66f31c5Sopenharmony_ci 2476e66f31c5Sopenharmony_ci for (;;) { 2477e66f31c5Sopenharmony_ci do 2478e66f31c5Sopenharmony_ci size = read(loop->inotify_fd, buf, sizeof(buf)); 2479e66f31c5Sopenharmony_ci while (size == -1 && errno == EINTR); 2480e66f31c5Sopenharmony_ci 2481e66f31c5Sopenharmony_ci if (size == -1) { 2482e66f31c5Sopenharmony_ci assert(errno == EAGAIN || errno == EWOULDBLOCK); 2483e66f31c5Sopenharmony_ci break; 2484e66f31c5Sopenharmony_ci } 2485e66f31c5Sopenharmony_ci 2486e66f31c5Sopenharmony_ci assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */ 2487e66f31c5Sopenharmony_ci 2488e66f31c5Sopenharmony_ci /* Now we have one or more inotify_event structs. */ 2489e66f31c5Sopenharmony_ci for (p = buf; p < buf + size; p += sizeof(*e) + e->len) { 2490e66f31c5Sopenharmony_ci e = (const struct inotify_event*) p; 2491e66f31c5Sopenharmony_ci 2492e66f31c5Sopenharmony_ci events = 0; 2493e66f31c5Sopenharmony_ci if (e->mask & (IN_ATTRIB|IN_MODIFY)) 2494e66f31c5Sopenharmony_ci events |= UV_CHANGE; 2495e66f31c5Sopenharmony_ci if (e->mask & ~(IN_ATTRIB|IN_MODIFY)) 2496e66f31c5Sopenharmony_ci events |= UV_RENAME; 2497e66f31c5Sopenharmony_ci 2498e66f31c5Sopenharmony_ci w = find_watcher(loop, e->wd); 2499e66f31c5Sopenharmony_ci if (w == NULL) 2500e66f31c5Sopenharmony_ci continue; /* Stale event, no watchers left. */ 2501e66f31c5Sopenharmony_ci 2502e66f31c5Sopenharmony_ci /* inotify does not return the filename when monitoring a single file 2503e66f31c5Sopenharmony_ci * for modifications. Repurpose the filename for API compatibility. 2504e66f31c5Sopenharmony_ci * I'm not convinced this is a good thing, maybe it should go. 2505e66f31c5Sopenharmony_ci */ 2506e66f31c5Sopenharmony_ci path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); 2507e66f31c5Sopenharmony_ci 2508e66f31c5Sopenharmony_ci /* We're about to iterate over the queue and call user's callbacks. 2509e66f31c5Sopenharmony_ci * What can go wrong? 2510e66f31c5Sopenharmony_ci * A callback could call uv_fs_event_stop() 2511e66f31c5Sopenharmony_ci * and the queue can change under our feet. 2512e66f31c5Sopenharmony_ci * So, we use uv__queue_move() trick to safely iterate over the queue. 2513e66f31c5Sopenharmony_ci * And we don't free the watcher_list until we're done iterating. 2514e66f31c5Sopenharmony_ci * 2515e66f31c5Sopenharmony_ci * First, 2516e66f31c5Sopenharmony_ci * tell uv_fs_event_stop() (that could be called from a user's callback) 2517e66f31c5Sopenharmony_ci * not to free watcher_list. 2518e66f31c5Sopenharmony_ci */ 2519e66f31c5Sopenharmony_ci w->iterating = 1; 2520e66f31c5Sopenharmony_ci uv__queue_move(&w->watchers, &queue); 2521e66f31c5Sopenharmony_ci while (!uv__queue_empty(&queue)) { 2522e66f31c5Sopenharmony_ci q = uv__queue_head(&queue); 2523e66f31c5Sopenharmony_ci h = uv__queue_data(q, uv_fs_event_t, watchers); 2524e66f31c5Sopenharmony_ci 2525e66f31c5Sopenharmony_ci uv__queue_remove(q); 2526e66f31c5Sopenharmony_ci uv__queue_insert_tail(&w->watchers, q); 2527e66f31c5Sopenharmony_ci 2528e66f31c5Sopenharmony_ci h->cb(h, path, events, 0); 2529e66f31c5Sopenharmony_ci } 2530e66f31c5Sopenharmony_ci /* done iterating, time to (maybe) free empty watcher_list */ 2531e66f31c5Sopenharmony_ci w->iterating = 0; 2532e66f31c5Sopenharmony_ci maybe_free_watcher_list(w, loop); 2533e66f31c5Sopenharmony_ci } 2534e66f31c5Sopenharmony_ci } 2535e66f31c5Sopenharmony_ci} 2536e66f31c5Sopenharmony_ci 2537e66f31c5Sopenharmony_ci 2538e66f31c5Sopenharmony_ciint uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) { 2539e66f31c5Sopenharmony_ci uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); 2540e66f31c5Sopenharmony_ci return 0; 2541e66f31c5Sopenharmony_ci} 2542e66f31c5Sopenharmony_ci 2543e66f31c5Sopenharmony_ci 2544e66f31c5Sopenharmony_ciint uv_fs_event_start(uv_fs_event_t* handle, 2545e66f31c5Sopenharmony_ci uv_fs_event_cb cb, 2546e66f31c5Sopenharmony_ci const char* path, 2547e66f31c5Sopenharmony_ci unsigned int flags) { 2548e66f31c5Sopenharmony_ci struct watcher_list* w; 2549e66f31c5Sopenharmony_ci uv_loop_t* loop; 2550e66f31c5Sopenharmony_ci size_t len; 2551e66f31c5Sopenharmony_ci int events; 2552e66f31c5Sopenharmony_ci int err; 2553e66f31c5Sopenharmony_ci int wd; 2554e66f31c5Sopenharmony_ci 2555e66f31c5Sopenharmony_ci if (uv__is_active(handle)) 2556e66f31c5Sopenharmony_ci return UV_EINVAL; 2557e66f31c5Sopenharmony_ci 2558e66f31c5Sopenharmony_ci loop = handle->loop; 2559e66f31c5Sopenharmony_ci 2560e66f31c5Sopenharmony_ci err = init_inotify(loop); 2561e66f31c5Sopenharmony_ci if (err) 2562e66f31c5Sopenharmony_ci return err; 2563e66f31c5Sopenharmony_ci 2564e66f31c5Sopenharmony_ci events = IN_ATTRIB 2565e66f31c5Sopenharmony_ci | IN_CREATE 2566e66f31c5Sopenharmony_ci | IN_MODIFY 2567e66f31c5Sopenharmony_ci | IN_DELETE 2568e66f31c5Sopenharmony_ci | IN_DELETE_SELF 2569e66f31c5Sopenharmony_ci | IN_MOVE_SELF 2570e66f31c5Sopenharmony_ci | IN_MOVED_FROM 2571e66f31c5Sopenharmony_ci | IN_MOVED_TO; 2572e66f31c5Sopenharmony_ci 2573e66f31c5Sopenharmony_ci wd = inotify_add_watch(loop->inotify_fd, path, events); 2574e66f31c5Sopenharmony_ci if (wd == -1) 2575e66f31c5Sopenharmony_ci return UV__ERR(errno); 2576e66f31c5Sopenharmony_ci 2577e66f31c5Sopenharmony_ci w = find_watcher(loop, wd); 2578e66f31c5Sopenharmony_ci if (w) 2579e66f31c5Sopenharmony_ci goto no_insert; 2580e66f31c5Sopenharmony_ci 2581e66f31c5Sopenharmony_ci len = strlen(path) + 1; 2582e66f31c5Sopenharmony_ci w = uv__malloc(sizeof(*w) + len); 2583e66f31c5Sopenharmony_ci if (w == NULL) 2584e66f31c5Sopenharmony_ci return UV_ENOMEM; 2585e66f31c5Sopenharmony_ci 2586e66f31c5Sopenharmony_ci w->wd = wd; 2587e66f31c5Sopenharmony_ci w->path = memcpy(w + 1, path, len); 2588e66f31c5Sopenharmony_ci uv__queue_init(&w->watchers); 2589e66f31c5Sopenharmony_ci w->iterating = 0; 2590e66f31c5Sopenharmony_ci RB_INSERT(watcher_root, uv__inotify_watchers(loop), w); 2591e66f31c5Sopenharmony_ci 2592e66f31c5Sopenharmony_cino_insert: 2593e66f31c5Sopenharmony_ci uv__handle_start(handle); 2594e66f31c5Sopenharmony_ci uv__queue_insert_tail(&w->watchers, &handle->watchers); 2595e66f31c5Sopenharmony_ci handle->path = w->path; 2596e66f31c5Sopenharmony_ci handle->cb = cb; 2597e66f31c5Sopenharmony_ci handle->wd = wd; 2598e66f31c5Sopenharmony_ci 2599e66f31c5Sopenharmony_ci return 0; 2600e66f31c5Sopenharmony_ci} 2601e66f31c5Sopenharmony_ci 2602e66f31c5Sopenharmony_ci 2603e66f31c5Sopenharmony_ciint uv_fs_event_stop(uv_fs_event_t* handle) { 2604e66f31c5Sopenharmony_ci struct watcher_list* w; 2605e66f31c5Sopenharmony_ci 2606e66f31c5Sopenharmony_ci if (!uv__is_active(handle)) 2607e66f31c5Sopenharmony_ci return 0; 2608e66f31c5Sopenharmony_ci 2609e66f31c5Sopenharmony_ci w = find_watcher(handle->loop, handle->wd); 2610e66f31c5Sopenharmony_ci assert(w != NULL); 2611e66f31c5Sopenharmony_ci 2612e66f31c5Sopenharmony_ci handle->wd = -1; 2613e66f31c5Sopenharmony_ci handle->path = NULL; 2614e66f31c5Sopenharmony_ci uv__handle_stop(handle); 2615e66f31c5Sopenharmony_ci uv__queue_remove(&handle->watchers); 2616e66f31c5Sopenharmony_ci 2617e66f31c5Sopenharmony_ci maybe_free_watcher_list(w, handle->loop); 2618e66f31c5Sopenharmony_ci 2619e66f31c5Sopenharmony_ci return 0; 2620e66f31c5Sopenharmony_ci} 2621e66f31c5Sopenharmony_ci 2622e66f31c5Sopenharmony_ci 2623e66f31c5Sopenharmony_civoid uv__fs_event_close(uv_fs_event_t* handle) { 2624e66f31c5Sopenharmony_ci uv_fs_event_stop(handle); 2625e66f31c5Sopenharmony_ci} 2626