11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) 2024 Brad House
41cb0ef41Sopenharmony_ci *
51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
141cb0ef41Sopenharmony_ci * Software.
151cb0ef41Sopenharmony_ci *
161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
221cb0ef41Sopenharmony_ci * SOFTWARE.
231cb0ef41Sopenharmony_ci *
241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ci#include "ares_setup.h"
271cb0ef41Sopenharmony_ci#include "ares.h"
281cb0ef41Sopenharmony_ci#include "ares_private.h"
291cb0ef41Sopenharmony_ci#include "ares_event.h"
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_EPOLL_H
321cb0ef41Sopenharmony_ci#  include <sys/epoll.h>
331cb0ef41Sopenharmony_ci#endif
341cb0ef41Sopenharmony_ci#ifdef HAVE_FCNTL_H
351cb0ef41Sopenharmony_ci#  include <fcntl.h>
361cb0ef41Sopenharmony_ci#endif
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci#ifdef HAVE_EPOLL
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_citypedef struct {
411cb0ef41Sopenharmony_ci  int epoll_fd;
421cb0ef41Sopenharmony_ci} ares_evsys_epoll_t;
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cistatic void ares_evsys_epoll_destroy(ares_event_thread_t *e)
451cb0ef41Sopenharmony_ci{
461cb0ef41Sopenharmony_ci  ares_evsys_epoll_t *ep = NULL;
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  if (e == NULL) {
491cb0ef41Sopenharmony_ci    return;
501cb0ef41Sopenharmony_ci  }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  ep = e->ev_sys_data;
531cb0ef41Sopenharmony_ci  if (ep == NULL) {
541cb0ef41Sopenharmony_ci    return;
551cb0ef41Sopenharmony_ci  }
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  if (ep->epoll_fd != -1) {
581cb0ef41Sopenharmony_ci    close(ep->epoll_fd);
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  ares_free(ep);
621cb0ef41Sopenharmony_ci  e->ev_sys_data = NULL;
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_cistatic ares_bool_t ares_evsys_epoll_init(ares_event_thread_t *e)
661cb0ef41Sopenharmony_ci{
671cb0ef41Sopenharmony_ci  ares_evsys_epoll_t *ep = NULL;
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  ep = ares_malloc_zero(sizeof(*ep));
701cb0ef41Sopenharmony_ci  if (ep == NULL) {
711cb0ef41Sopenharmony_ci    return ARES_FALSE;
721cb0ef41Sopenharmony_ci  }
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  e->ev_sys_data = ep;
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  ep->epoll_fd = epoll_create1(0);
771cb0ef41Sopenharmony_ci  if (ep->epoll_fd == -1) {
781cb0ef41Sopenharmony_ci    ares_evsys_epoll_destroy(e);
791cb0ef41Sopenharmony_ci    return ARES_FALSE;
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci#  ifdef FD_CLOEXEC
831cb0ef41Sopenharmony_ci  fcntl(ep->epoll_fd, F_SETFD, FD_CLOEXEC);
841cb0ef41Sopenharmony_ci#  endif
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  e->ev_signal = ares_pipeevent_create(e);
871cb0ef41Sopenharmony_ci  if (e->ev_signal == NULL) {
881cb0ef41Sopenharmony_ci    ares_evsys_epoll_destroy(e);
891cb0ef41Sopenharmony_ci    return ARES_FALSE;
901cb0ef41Sopenharmony_ci  }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  return ARES_TRUE;
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_cistatic ares_bool_t ares_evsys_epoll_event_add(ares_event_t *event)
961cb0ef41Sopenharmony_ci{
971cb0ef41Sopenharmony_ci  const ares_event_thread_t *e  = event->e;
981cb0ef41Sopenharmony_ci  const ares_evsys_epoll_t  *ep = e->ev_sys_data;
991cb0ef41Sopenharmony_ci  struct epoll_event         epev;
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  memset(&epev, 0, sizeof(epev));
1021cb0ef41Sopenharmony_ci  epev.data.fd = event->fd;
1031cb0ef41Sopenharmony_ci  epev.events  = EPOLLRDHUP | EPOLLERR | EPOLLHUP;
1041cb0ef41Sopenharmony_ci  if (event->flags & ARES_EVENT_FLAG_READ) {
1051cb0ef41Sopenharmony_ci    epev.events |= EPOLLIN;
1061cb0ef41Sopenharmony_ci  }
1071cb0ef41Sopenharmony_ci  if (event->flags & ARES_EVENT_FLAG_WRITE) {
1081cb0ef41Sopenharmony_ci    epev.events |= EPOLLOUT;
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci  if (epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, event->fd, &epev) != 0) {
1111cb0ef41Sopenharmony_ci    return ARES_FALSE;
1121cb0ef41Sopenharmony_ci  }
1131cb0ef41Sopenharmony_ci  return ARES_TRUE;
1141cb0ef41Sopenharmony_ci}
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_cistatic void ares_evsys_epoll_event_del(ares_event_t *event)
1171cb0ef41Sopenharmony_ci{
1181cb0ef41Sopenharmony_ci  const ares_event_thread_t *e  = event->e;
1191cb0ef41Sopenharmony_ci  const ares_evsys_epoll_t  *ep = e->ev_sys_data;
1201cb0ef41Sopenharmony_ci  struct epoll_event         epev;
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  memset(&epev, 0, sizeof(epev));
1231cb0ef41Sopenharmony_ci  epev.data.fd = event->fd;
1241cb0ef41Sopenharmony_ci  epoll_ctl(ep->epoll_fd, EPOLL_CTL_DEL, event->fd, &epev);
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_cistatic void ares_evsys_epoll_event_mod(ares_event_t      *event,
1281cb0ef41Sopenharmony_ci                                       ares_event_flags_t new_flags)
1291cb0ef41Sopenharmony_ci{
1301cb0ef41Sopenharmony_ci  const ares_event_thread_t *e  = event->e;
1311cb0ef41Sopenharmony_ci  const ares_evsys_epoll_t  *ep = e->ev_sys_data;
1321cb0ef41Sopenharmony_ci  struct epoll_event         epev;
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  memset(&epev, 0, sizeof(epev));
1351cb0ef41Sopenharmony_ci  epev.data.fd = event->fd;
1361cb0ef41Sopenharmony_ci  epev.events  = EPOLLRDHUP | EPOLLERR | EPOLLHUP;
1371cb0ef41Sopenharmony_ci  if (new_flags & ARES_EVENT_FLAG_READ) {
1381cb0ef41Sopenharmony_ci    epev.events |= EPOLLIN;
1391cb0ef41Sopenharmony_ci  }
1401cb0ef41Sopenharmony_ci  if (new_flags & ARES_EVENT_FLAG_WRITE) {
1411cb0ef41Sopenharmony_ci    epev.events |= EPOLLOUT;
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci  epoll_ctl(ep->epoll_fd, EPOLL_CTL_MOD, event->fd, &epev);
1441cb0ef41Sopenharmony_ci}
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_cistatic size_t ares_evsys_epoll_wait(ares_event_thread_t *e,
1471cb0ef41Sopenharmony_ci                                    unsigned long        timeout_ms)
1481cb0ef41Sopenharmony_ci{
1491cb0ef41Sopenharmony_ci  struct epoll_event        events[8];
1501cb0ef41Sopenharmony_ci  size_t                    nevents = sizeof(events) / sizeof(*events);
1511cb0ef41Sopenharmony_ci  const ares_evsys_epoll_t *ep      = e->ev_sys_data;
1521cb0ef41Sopenharmony_ci  int                       rv;
1531cb0ef41Sopenharmony_ci  size_t                    i;
1541cb0ef41Sopenharmony_ci  size_t                    cnt = 0;
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  memset(events, 0, sizeof(events));
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  rv = epoll_wait(ep->epoll_fd, events, (int)nevents,
1591cb0ef41Sopenharmony_ci                  (timeout_ms == 0) ? -1 : (int)timeout_ms);
1601cb0ef41Sopenharmony_ci  if (rv < 0) {
1611cb0ef41Sopenharmony_ci    return 0;
1621cb0ef41Sopenharmony_ci  }
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  nevents = (size_t)rv;
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  for (i = 0; i < nevents; i++) {
1671cb0ef41Sopenharmony_ci    ares_event_t      *ev;
1681cb0ef41Sopenharmony_ci    ares_event_flags_t flags = 0;
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    ev = ares__htable_asvp_get_direct(e->ev_handles,
1711cb0ef41Sopenharmony_ci                                      (ares_socket_t)events[i].data.fd);
1721cb0ef41Sopenharmony_ci    if (ev == NULL || ev->cb == NULL) {
1731cb0ef41Sopenharmony_ci      continue;
1741cb0ef41Sopenharmony_ci    }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    cnt++;
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci    if (events[i].events & (EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
1791cb0ef41Sopenharmony_ci      flags |= ARES_EVENT_FLAG_READ;
1801cb0ef41Sopenharmony_ci    }
1811cb0ef41Sopenharmony_ci    if (events[i].events & EPOLLOUT) {
1821cb0ef41Sopenharmony_ci      flags |= ARES_EVENT_FLAG_WRITE;
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci    ev->cb(e, ev->fd, ev->data, flags);
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci  return cnt;
1891cb0ef41Sopenharmony_ci}
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ciconst ares_event_sys_t ares_evsys_epoll = { "epoll",
1921cb0ef41Sopenharmony_ci                                            ares_evsys_epoll_init,
1931cb0ef41Sopenharmony_ci                                            ares_evsys_epoll_destroy,
1941cb0ef41Sopenharmony_ci                                            ares_evsys_epoll_event_add,
1951cb0ef41Sopenharmony_ci                                            ares_evsys_epoll_event_del,
1961cb0ef41Sopenharmony_ci                                            ares_evsys_epoll_event_mod,
1971cb0ef41Sopenharmony_ci                                            ares_evsys_epoll_wait };
1981cb0ef41Sopenharmony_ci#endif
199