quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ares_event_epoll.c (5806B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 2024 Brad House
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  * SPDX-License-Identifier: MIT
     25  */
     26 #include "ares_private.h"
     27 #include "ares_event.h"
     28 
     29 #if defined(HAVE_EPOLL) && defined(CARES_THREADS)
     30 
     31 #ifdef HAVE_SYS_EPOLL_H
     32 #  include <sys/epoll.h>
     33 #endif
     34 #ifdef HAVE_FCNTL_H
     35 #  include <fcntl.h>
     36 #endif
     37 
     38 typedef struct {
     39   int epoll_fd;
     40 } ares_evsys_epoll_t;
     41 
     42 static void ares_evsys_epoll_destroy(ares_event_thread_t *e)
     43 {
     44   ares_evsys_epoll_t *ep = NULL;
     45 
     46   if (e == NULL) {
     47     return; /* LCOV_EXCL_LINE: DefensiveCoding */
     48   }
     49 
     50   ep = e->ev_sys_data;
     51   if (ep == NULL) {
     52     return; /* LCOV_EXCL_LINE: DefensiveCoding */
     53   }
     54 
     55   if (ep->epoll_fd != -1) {
     56     close(ep->epoll_fd);
     57   }
     58 
     59   ares_free(ep);
     60   e->ev_sys_data = NULL;
     61 }
     62 
     63 static ares_bool_t ares_evsys_epoll_init(ares_event_thread_t *e)
     64 {
     65   ares_evsys_epoll_t *ep = NULL;
     66 
     67   ep = ares_malloc_zero(sizeof(*ep));
     68   if (ep == NULL) {
     69     return ARES_FALSE; /* LCOV_EXCL_LINE: OutOfMemory */
     70   }
     71 
     72   e->ev_sys_data = ep;
     73 
     74   ep->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
     75   if (ep->epoll_fd == -1) {
     76     ares_evsys_epoll_destroy(e); /* LCOV_EXCL_LINE: UntestablePath */
     77     return ARES_FALSE;           /* LCOV_EXCL_LINE: UntestablePath */
     78   }
     79 
     80   e->ev_signal = ares_pipeevent_create(e);
     81   if (e->ev_signal == NULL) {
     82     ares_evsys_epoll_destroy(e); /* LCOV_EXCL_LINE: UntestablePath */
     83     return ARES_FALSE;           /* LCOV_EXCL_LINE: UntestablePath */
     84   }
     85 
     86   return ARES_TRUE;
     87 }
     88 
     89 static ares_bool_t ares_evsys_epoll_event_add(ares_event_t *event)
     90 {
     91   const ares_event_thread_t *e  = event->e;
     92   const ares_evsys_epoll_t  *ep = e->ev_sys_data;
     93   struct epoll_event         epev;
     94 
     95   memset(&epev, 0, sizeof(epev));
     96   epev.data.fd = event->fd;
     97   epev.events  = EPOLLRDHUP | EPOLLERR | EPOLLHUP;
     98   if (event->flags & ARES_EVENT_FLAG_READ) {
     99     epev.events |= EPOLLIN;
    100   }
    101   if (event->flags & ARES_EVENT_FLAG_WRITE) {
    102     epev.events |= EPOLLOUT;
    103   }
    104   if (epoll_ctl(ep->epoll_fd, EPOLL_CTL_ADD, event->fd, &epev) != 0) {
    105     return ARES_FALSE; /* LCOV_EXCL_LINE: UntestablePath */
    106   }
    107   return ARES_TRUE;
    108 }
    109 
    110 static void ares_evsys_epoll_event_del(ares_event_t *event)
    111 {
    112   const ares_event_thread_t *e  = event->e;
    113   const ares_evsys_epoll_t  *ep = e->ev_sys_data;
    114   struct epoll_event         epev;
    115 
    116   memset(&epev, 0, sizeof(epev));
    117   epev.data.fd = event->fd;
    118   epoll_ctl(ep->epoll_fd, EPOLL_CTL_DEL, event->fd, &epev);
    119 }
    120 
    121 static void ares_evsys_epoll_event_mod(ares_event_t      *event,
    122                                        ares_event_flags_t new_flags)
    123 {
    124   const ares_event_thread_t *e  = event->e;
    125   const ares_evsys_epoll_t  *ep = e->ev_sys_data;
    126   struct epoll_event         epev;
    127 
    128   memset(&epev, 0, sizeof(epev));
    129   epev.data.fd = event->fd;
    130   epev.events  = EPOLLRDHUP | EPOLLERR | EPOLLHUP;
    131   if (new_flags & ARES_EVENT_FLAG_READ) {
    132     epev.events |= EPOLLIN;
    133   }
    134   if (new_flags & ARES_EVENT_FLAG_WRITE) {
    135     epev.events |= EPOLLOUT;
    136   }
    137   epoll_ctl(ep->epoll_fd, EPOLL_CTL_MOD, event->fd, &epev);
    138 }
    139 
    140 static size_t ares_evsys_epoll_wait(ares_event_thread_t *e,
    141                                     unsigned long        timeout_ms)
    142 {
    143   struct epoll_event        events[8];
    144   size_t                    nevents = sizeof(events) / sizeof(*events);
    145   const ares_evsys_epoll_t *ep      = e->ev_sys_data;
    146   int                       rv;
    147   size_t                    i;
    148   size_t                    cnt = 0;
    149 
    150   memset(events, 0, sizeof(events));
    151 
    152   rv = epoll_wait(ep->epoll_fd, events, (int)nevents,
    153                   (timeout_ms == 0) ? -1 : (int)timeout_ms);
    154   if (rv < 0) {
    155     return 0; /* LCOV_EXCL_LINE: UntestablePath */
    156   }
    157 
    158   nevents = (size_t)rv;
    159 
    160   for (i = 0; i < nevents; i++) {
    161     ares_event_t      *ev;
    162     ares_event_flags_t flags = 0;
    163 
    164     ev = ares_htable_asvp_get_direct(e->ev_sock_handles,
    165                                      (ares_socket_t)events[i].data.fd);
    166     if (ev == NULL || ev->cb == NULL) {
    167       continue; /* LCOV_EXCL_LINE: DefensiveCoding */
    168     }
    169 
    170     cnt++;
    171 
    172     if (events[i].events & (EPOLLIN | EPOLLRDHUP | EPOLLHUP | EPOLLERR)) {
    173       flags |= ARES_EVENT_FLAG_READ;
    174     }
    175     if (events[i].events & EPOLLOUT) {
    176       flags |= ARES_EVENT_FLAG_WRITE;
    177     }
    178 
    179     ev->cb(e, ev->fd, ev->data, flags);
    180   }
    181 
    182   return cnt;
    183 }
    184 
    185 const ares_event_sys_t ares_evsys_epoll = { "epoll",
    186                                             ares_evsys_epoll_init,
    187                                             ares_evsys_epoll_destroy,
    188                                             ares_evsys_epoll_event_add,
    189                                             ares_evsys_epoll_event_del,
    190                                             ares_evsys_epoll_event_mod,
    191                                             ares_evsys_epoll_wait };
    192 #endif