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/* This file contains both the uv__async internal infrastructure and the
22e66f31c5Sopenharmony_ci * user-facing uv_async_t functions.
23e66f31c5Sopenharmony_ci */
24e66f31c5Sopenharmony_ci
25e66f31c5Sopenharmony_ci#include "uv.h"
26e66f31c5Sopenharmony_ci#include "internal.h"
27e66f31c5Sopenharmony_ci#include "uv_log.h"
28e66f31c5Sopenharmony_ci
29e66f31c5Sopenharmony_ci#include <errno.h>
30e66f31c5Sopenharmony_ci#include <stdatomic.h>
31e66f31c5Sopenharmony_ci#include <stdio.h>  /* snprintf() */
32e66f31c5Sopenharmony_ci#include <assert.h>
33e66f31c5Sopenharmony_ci#include <stdlib.h>
34e66f31c5Sopenharmony_ci#include <string.h>
35e66f31c5Sopenharmony_ci#include <unistd.h>
36e66f31c5Sopenharmony_ci#include <sched.h>  /* sched_yield() */
37e66f31c5Sopenharmony_ci
38e66f31c5Sopenharmony_ci#ifdef __linux__
39e66f31c5Sopenharmony_ci#include <sys/eventfd.h>
40e66f31c5Sopenharmony_ci#endif
41e66f31c5Sopenharmony_ci
42e66f31c5Sopenharmony_ci#ifdef USE_FFRT
43e66f31c5Sopenharmony_ci#include "ffrt.h"
44e66f31c5Sopenharmony_ci#include "c/executor_task.h"
45e66f31c5Sopenharmony_ci#endif
46e66f31c5Sopenharmony_ci
47e66f31c5Sopenharmony_cistatic void uv__async_send(uv_async_t* handle);
48e66f31c5Sopenharmony_cistatic int uv__async_start(uv_loop_t* loop);
49e66f31c5Sopenharmony_ci
50e66f31c5Sopenharmony_ci
51e66f31c5Sopenharmony_ciint uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
52e66f31c5Sopenharmony_ci  int err;
53e66f31c5Sopenharmony_ci
54e66f31c5Sopenharmony_ci  err = uv__async_start(loop);
55e66f31c5Sopenharmony_ci  if (err)
56e66f31c5Sopenharmony_ci    return err;
57e66f31c5Sopenharmony_ci
58e66f31c5Sopenharmony_ci  uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
59e66f31c5Sopenharmony_ci  handle->async_cb = async_cb;
60e66f31c5Sopenharmony_ci  handle->pending = 0;
61e66f31c5Sopenharmony_ci
62e66f31c5Sopenharmony_ci  uv__queue_insert_tail(&loop->async_handles, &handle->queue);
63e66f31c5Sopenharmony_ci  uv__handle_start(handle);
64e66f31c5Sopenharmony_ci
65e66f31c5Sopenharmony_ci  return 0;
66e66f31c5Sopenharmony_ci}
67e66f31c5Sopenharmony_ci
68e66f31c5Sopenharmony_ci
69e66f31c5Sopenharmony_ciint uv_async_send(uv_async_t* handle) {
70e66f31c5Sopenharmony_ci  _Atomic int* pending;
71e66f31c5Sopenharmony_ci
72e66f31c5Sopenharmony_ci#ifdef USE_OHOS_DFX
73e66f31c5Sopenharmony_ci  if (handle == NULL) {
74e66f31c5Sopenharmony_ci    UV_LOGF("handle is NULL");
75e66f31c5Sopenharmony_ci    return -1;
76e66f31c5Sopenharmony_ci  }
77e66f31c5Sopenharmony_ci#endif
78e66f31c5Sopenharmony_ci
79e66f31c5Sopenharmony_ci  pending = (_Atomic int*) &handle->pending;
80e66f31c5Sopenharmony_ci
81e66f31c5Sopenharmony_ci
82e66f31c5Sopenharmony_ci  /* Do a cheap read first. */
83e66f31c5Sopenharmony_ci  if (atomic_load_explicit(pending, memory_order_relaxed) != 0)
84e66f31c5Sopenharmony_ci    return 0;
85e66f31c5Sopenharmony_ci
86e66f31c5Sopenharmony_ci  /* Wake up the other thread's event loop. */
87e66f31c5Sopenharmony_ci  if (atomic_exchange(pending, 1) != 0)
88e66f31c5Sopenharmony_ci    return 0;
89e66f31c5Sopenharmony_ci
90e66f31c5Sopenharmony_ci  /* Wake up the other thread's event loop. */
91e66f31c5Sopenharmony_ci  uv__async_send(handle);
92e66f31c5Sopenharmony_ci  return 0;
93e66f31c5Sopenharmony_ci}
94e66f31c5Sopenharmony_ci
95e66f31c5Sopenharmony_ci
96e66f31c5Sopenharmony_ci
97e66f31c5Sopenharmony_civoid uv__async_close(uv_async_t* handle) {
98e66f31c5Sopenharmony_ci  atomic_exchange((_Atomic int*) &handle->pending, 0);
99e66f31c5Sopenharmony_ci  uv__queue_remove(&handle->queue);
100e66f31c5Sopenharmony_ci  uv__handle_stop(handle);
101e66f31c5Sopenharmony_ci}
102e66f31c5Sopenharmony_ci
103e66f31c5Sopenharmony_ci
104e66f31c5Sopenharmony_cistatic void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
105e66f31c5Sopenharmony_ci  char buf[1024];
106e66f31c5Sopenharmony_ci  ssize_t r;
107e66f31c5Sopenharmony_ci  struct uv__queue queue;
108e66f31c5Sopenharmony_ci  struct uv__queue* q;
109e66f31c5Sopenharmony_ci  uv_async_t* h;
110e66f31c5Sopenharmony_ci  _Atomic int *pending;
111e66f31c5Sopenharmony_ci
112e66f31c5Sopenharmony_ci  assert(w == &loop->async_io_watcher);
113e66f31c5Sopenharmony_ci
114e66f31c5Sopenharmony_ci  for (;;) {
115e66f31c5Sopenharmony_ci    r = read(w->fd, buf, sizeof(buf));
116e66f31c5Sopenharmony_ci
117e66f31c5Sopenharmony_ci    if (r == sizeof(buf))
118e66f31c5Sopenharmony_ci      continue;
119e66f31c5Sopenharmony_ci
120e66f31c5Sopenharmony_ci    if (r != -1)
121e66f31c5Sopenharmony_ci      break;
122e66f31c5Sopenharmony_ci
123e66f31c5Sopenharmony_ci    if (errno == EAGAIN || errno == EWOULDBLOCK)
124e66f31c5Sopenharmony_ci      break;
125e66f31c5Sopenharmony_ci
126e66f31c5Sopenharmony_ci    if (errno == EINTR)
127e66f31c5Sopenharmony_ci      continue;
128e66f31c5Sopenharmony_ci
129e66f31c5Sopenharmony_ci#ifdef PRINT_ERRNO_ABORT
130e66f31c5Sopenharmony_ci    UV_ERRNO_ABORT("errno is %d, loop addr is %zu, fd is %d (%s:%s:%d)",
131e66f31c5Sopenharmony_ci      errno, (size_t)loop, w->fd, __FILE__, __func__, __LINE__);
132e66f31c5Sopenharmony_ci#else
133e66f31c5Sopenharmony_ci    abort();
134e66f31c5Sopenharmony_ci#endif
135e66f31c5Sopenharmony_ci  }
136e66f31c5Sopenharmony_ci
137e66f31c5Sopenharmony_ci  uv__queue_move(&loop->async_handles, &queue);
138e66f31c5Sopenharmony_ci  while (!uv__queue_empty(&queue)) {
139e66f31c5Sopenharmony_ci    q = uv__queue_head(&queue);
140e66f31c5Sopenharmony_ci    h = uv__queue_data(q, uv_async_t, queue);
141e66f31c5Sopenharmony_ci
142e66f31c5Sopenharmony_ci    uv__queue_remove(q);
143e66f31c5Sopenharmony_ci    uv__queue_insert_tail(&loop->async_handles, q);
144e66f31c5Sopenharmony_ci
145e66f31c5Sopenharmony_ci    /* Atomically fetch and clear pending flag */
146e66f31c5Sopenharmony_ci    pending = (_Atomic int*) &h->pending;
147e66f31c5Sopenharmony_ci    if (atomic_exchange(pending, 0) == 0)
148e66f31c5Sopenharmony_ci      continue;
149e66f31c5Sopenharmony_ci
150e66f31c5Sopenharmony_ci    if (h->async_cb == NULL)
151e66f31c5Sopenharmony_ci      continue;
152e66f31c5Sopenharmony_ci
153e66f31c5Sopenharmony_ci    h->async_cb(h);
154e66f31c5Sopenharmony_ci  }
155e66f31c5Sopenharmony_ci}
156e66f31c5Sopenharmony_ci
157e66f31c5Sopenharmony_ci
158e66f31c5Sopenharmony_cistatic void uv__async_send(uv_async_t* handle) {
159e66f31c5Sopenharmony_ci  const void* buf;
160e66f31c5Sopenharmony_ci  ssize_t len;
161e66f31c5Sopenharmony_ci  int fd;
162e66f31c5Sopenharmony_ci  int r;
163e66f31c5Sopenharmony_ci
164e66f31c5Sopenharmony_ci  uv_loop_t* loop = handle->loop;
165e66f31c5Sopenharmony_ci  if (loop == NULL) {
166e66f31c5Sopenharmony_ci    UV_LOGF("loop is NULL");
167e66f31c5Sopenharmony_ci    return;
168e66f31c5Sopenharmony_ci  }
169e66f31c5Sopenharmony_ci
170e66f31c5Sopenharmony_ci  buf = "";
171e66f31c5Sopenharmony_ci  len = 1;
172e66f31c5Sopenharmony_ci  fd = loop->async_wfd;
173e66f31c5Sopenharmony_ci
174e66f31c5Sopenharmony_ci#if defined(__linux__)
175e66f31c5Sopenharmony_ci  if (fd == -1) {
176e66f31c5Sopenharmony_ci    static const uint64_t val = 1;
177e66f31c5Sopenharmony_ci    buf = &val;
178e66f31c5Sopenharmony_ci    len = sizeof(val);
179e66f31c5Sopenharmony_ci    fd = loop->async_io_watcher.fd;  /* eventfd */
180e66f31c5Sopenharmony_ci  }
181e66f31c5Sopenharmony_ci#endif
182e66f31c5Sopenharmony_ci
183e66f31c5Sopenharmony_ci  do
184e66f31c5Sopenharmony_ci    r = write(fd, buf, len);
185e66f31c5Sopenharmony_ci  while (r == -1 && errno == EINTR && atomic_load_explicit((_Atomic int*) &handle->pending, memory_order_relaxed) == 1);
186e66f31c5Sopenharmony_ci
187e66f31c5Sopenharmony_ci  if (r == len)
188e66f31c5Sopenharmony_ci    return;
189e66f31c5Sopenharmony_ci
190e66f31c5Sopenharmony_ci  if (r == -1)
191e66f31c5Sopenharmony_ci    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
192e66f31c5Sopenharmony_ci      return;
193e66f31c5Sopenharmony_ci
194e66f31c5Sopenharmony_ci#ifdef PRINT_ERRNO_ABORT
195e66f31c5Sopenharmony_ci    UV_ERRNO_ABORT("errno is %d, loop addr is %zu, fd is %d (%s:%s:%d)",
196e66f31c5Sopenharmony_ci      errno, (size_t)loop, fd, __FILE__, __func__, __LINE__);
197e66f31c5Sopenharmony_ci#else
198e66f31c5Sopenharmony_ci    abort();
199e66f31c5Sopenharmony_ci#endif
200e66f31c5Sopenharmony_ci}
201e66f31c5Sopenharmony_ci
202e66f31c5Sopenharmony_ci
203e66f31c5Sopenharmony_cistatic int uv__async_start(uv_loop_t* loop) {
204e66f31c5Sopenharmony_ci  int pipefd[2];
205e66f31c5Sopenharmony_ci  int err;
206e66f31c5Sopenharmony_ci
207e66f31c5Sopenharmony_ci  if (loop->async_io_watcher.fd != -1)
208e66f31c5Sopenharmony_ci    return 0;
209e66f31c5Sopenharmony_ci
210e66f31c5Sopenharmony_ci#ifdef __linux__
211e66f31c5Sopenharmony_ci  err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
212e66f31c5Sopenharmony_ci  if (err < 0)
213e66f31c5Sopenharmony_ci    return UV__ERR(errno);
214e66f31c5Sopenharmony_ci
215e66f31c5Sopenharmony_ci  pipefd[0] = err;
216e66f31c5Sopenharmony_ci  pipefd[1] = -1;
217e66f31c5Sopenharmony_ci#ifdef USE_OHOS_DFX
218e66f31c5Sopenharmony_ci  fdsan_exchange_owner_tag(pipefd[0], 0, uv__get_addr_tag((void *)&loop->async_io_watcher));
219e66f31c5Sopenharmony_ci#endif
220e66f31c5Sopenharmony_ci#else
221e66f31c5Sopenharmony_ci  err = uv__make_pipe(pipefd, UV_NONBLOCK_PIPE);
222e66f31c5Sopenharmony_ci  if (err < 0)
223e66f31c5Sopenharmony_ci    return err;
224e66f31c5Sopenharmony_ci#endif
225e66f31c5Sopenharmony_ci
226e66f31c5Sopenharmony_ci  uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
227e66f31c5Sopenharmony_ci  uv__io_start(loop, &loop->async_io_watcher, POLLIN);
228e66f31c5Sopenharmony_ci  loop->async_wfd = pipefd[1];
229e66f31c5Sopenharmony_ci  UV_LOGI("open:%{public}zu, pipefd[0]:%{public}d", (size_t)loop, pipefd[0]);
230e66f31c5Sopenharmony_ci  return 0;
231e66f31c5Sopenharmony_ci}
232e66f31c5Sopenharmony_ci
233e66f31c5Sopenharmony_ci
234e66f31c5Sopenharmony_ciint uv__async_fork(uv_loop_t* loop) {
235e66f31c5Sopenharmony_ci  if (loop->async_io_watcher.fd == -1) /* never started */
236e66f31c5Sopenharmony_ci    return 0;
237e66f31c5Sopenharmony_ci
238e66f31c5Sopenharmony_ci  uv__async_stop(loop);
239e66f31c5Sopenharmony_ci
240e66f31c5Sopenharmony_ci  return uv__async_start(loop);
241e66f31c5Sopenharmony_ci}
242e66f31c5Sopenharmony_ci
243e66f31c5Sopenharmony_ci
244e66f31c5Sopenharmony_civoid uv__async_stop(uv_loop_t* loop) {
245e66f31c5Sopenharmony_ci  if (loop->async_io_watcher.fd == -1)
246e66f31c5Sopenharmony_ci    return;
247e66f31c5Sopenharmony_ci
248e66f31c5Sopenharmony_ci  if (loop->async_wfd != -1) {
249e66f31c5Sopenharmony_ci    if (loop->async_wfd != loop->async_io_watcher.fd) {
250e66f31c5Sopenharmony_ci      UV_LOGI("close:%{public}zu, async_wfd:%{public}d", (size_t)loop, loop->async_wfd);
251e66f31c5Sopenharmony_ci      uv__close(loop->async_wfd);
252e66f31c5Sopenharmony_ci    }
253e66f31c5Sopenharmony_ci    loop->async_wfd = -1;
254e66f31c5Sopenharmony_ci  }
255e66f31c5Sopenharmony_ci
256e66f31c5Sopenharmony_ci  uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
257e66f31c5Sopenharmony_ci#ifdef USE_FFRT
258e66f31c5Sopenharmony_ci  if (ffrt_get_cur_task() != NULL) {
259e66f31c5Sopenharmony_ci    uv__epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, loop->async_io_watcher.fd, NULL);
260e66f31c5Sopenharmony_ci  }
261e66f31c5Sopenharmony_ci#endif
262e66f31c5Sopenharmony_ci
263e66f31c5Sopenharmony_ci#if defined(__linux__) && defined(USE_OHOS_DFX)
264e66f31c5Sopenharmony_ci  fdsan_close_with_tag(loop->async_io_watcher.fd, uv__get_addr_tag((void *)&loop->async_io_watcher));
265e66f31c5Sopenharmony_ci#else
266e66f31c5Sopenharmony_ci  uv__close(loop->async_io_watcher.fd);
267e66f31c5Sopenharmony_ci#endif
268e66f31c5Sopenharmony_ci  UV_LOGI("close:%{public}zu, async_io_wfd:%{public}d", (size_t)loop, loop->async_io_watcher.fd);
269e66f31c5Sopenharmony_ci  loop->async_io_watcher.fd = -1;
270e66f31c5Sopenharmony_ci}
271e66f31c5Sopenharmony_ci
272