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(&params, 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, &params);
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