quickjs-tart

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

ares_event_kqueue.c (6751B)


      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_KQUEUE) && defined(CARES_THREADS)
     30 
     31 #ifdef HAVE_SYS_TYPES_H
     32 #  include <sys/types.h>
     33 #endif
     34 #ifdef HAVE_SYS_EVENT_H
     35 #  include <sys/event.h>
     36 #endif
     37 #ifdef HAVE_SYS_TIME_H
     38 #  include <sys/time.h>
     39 #endif
     40 #ifdef HAVE_FCNTL_H
     41 #  include <fcntl.h>
     42 #endif
     43 
     44 typedef struct {
     45   int            kqueue_fd;
     46   struct kevent *changelist;
     47   size_t         nchanges;
     48   size_t         nchanges_alloc;
     49 } ares_evsys_kqueue_t;
     50 
     51 static void ares_evsys_kqueue_destroy(ares_event_thread_t *e)
     52 {
     53   ares_evsys_kqueue_t *kq = NULL;
     54 
     55   if (e == NULL) {
     56     return;
     57   }
     58 
     59   kq = e->ev_sys_data;
     60   if (kq == NULL) {
     61     return;
     62   }
     63 
     64   if (kq->kqueue_fd != -1) {
     65     close(kq->kqueue_fd);
     66   }
     67 
     68   ares_free(kq->changelist);
     69   ares_free(kq);
     70   e->ev_sys_data = NULL;
     71 }
     72 
     73 static ares_bool_t ares_evsys_kqueue_init(ares_event_thread_t *e)
     74 {
     75   ares_evsys_kqueue_t *kq = NULL;
     76 
     77   kq = ares_malloc_zero(sizeof(*kq));
     78   if (kq == NULL) {
     79     return ARES_FALSE;
     80   }
     81 
     82   e->ev_sys_data = kq;
     83 
     84   kq->kqueue_fd = kqueue();
     85   if (kq->kqueue_fd == -1) {
     86     ares_evsys_kqueue_destroy(e);
     87     return ARES_FALSE;
     88   }
     89 
     90 #  ifdef FD_CLOEXEC
     91   fcntl(kq->kqueue_fd, F_SETFD, FD_CLOEXEC);
     92 #  endif
     93 
     94   kq->nchanges_alloc = 8;
     95   kq->changelist =
     96     ares_malloc_zero(kq->nchanges_alloc * sizeof(*kq->changelist));
     97   if (kq->changelist == NULL) {
     98     ares_evsys_kqueue_destroy(e);
     99     return ARES_FALSE;
    100   }
    101 
    102   e->ev_signal = ares_pipeevent_create(e);
    103   if (e->ev_signal == NULL) {
    104     ares_evsys_kqueue_destroy(e);
    105     return ARES_FALSE;
    106   }
    107 
    108   return ARES_TRUE;
    109 }
    110 
    111 static void ares_evsys_kqueue_enqueue(ares_evsys_kqueue_t *kq, int fd,
    112                                       int16_t filter, uint16_t flags)
    113 {
    114   size_t idx;
    115 
    116   if (kq == NULL) {
    117     return;
    118   }
    119 
    120   idx = kq->nchanges;
    121 
    122   kq->nchanges++;
    123 
    124   if (kq->nchanges > kq->nchanges_alloc) {
    125     kq->nchanges_alloc <<= 1;
    126     kq->changelist       = ares_realloc_zero(
    127       kq->changelist, (kq->nchanges_alloc >> 1) * sizeof(*kq->changelist),
    128       kq->nchanges_alloc * sizeof(*kq->changelist));
    129   }
    130 
    131   EV_SET(&kq->changelist[idx], fd, filter, flags, 0, 0, 0);
    132 }
    133 
    134 static void ares_evsys_kqueue_event_process(ares_event_t      *event,
    135                                             ares_event_flags_t old_flags,
    136                                             ares_event_flags_t new_flags)
    137 {
    138   ares_event_thread_t *e = event->e;
    139   ares_evsys_kqueue_t *kq;
    140 
    141   if (e == NULL) {
    142     return;
    143   }
    144 
    145   kq = e->ev_sys_data;
    146   if (kq == NULL) {
    147     return;
    148   }
    149 
    150   if (new_flags & ARES_EVENT_FLAG_READ && !(old_flags & ARES_EVENT_FLAG_READ)) {
    151     ares_evsys_kqueue_enqueue(kq, event->fd, EVFILT_READ, EV_ADD | EV_ENABLE);
    152   }
    153 
    154   if (!(new_flags & ARES_EVENT_FLAG_READ) && old_flags & ARES_EVENT_FLAG_READ) {
    155     ares_evsys_kqueue_enqueue(kq, event->fd, EVFILT_READ, EV_DELETE);
    156   }
    157 
    158   if (new_flags & ARES_EVENT_FLAG_WRITE &&
    159       !(old_flags & ARES_EVENT_FLAG_WRITE)) {
    160     ares_evsys_kqueue_enqueue(kq, event->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE);
    161   }
    162 
    163   if (!(new_flags & ARES_EVENT_FLAG_WRITE) &&
    164       old_flags & ARES_EVENT_FLAG_WRITE) {
    165     ares_evsys_kqueue_enqueue(kq, event->fd, EVFILT_WRITE, EV_DELETE);
    166   }
    167 }
    168 
    169 static ares_bool_t ares_evsys_kqueue_event_add(ares_event_t *event)
    170 {
    171   ares_evsys_kqueue_event_process(event, 0, event->flags);
    172   return ARES_TRUE;
    173 }
    174 
    175 static void ares_evsys_kqueue_event_del(ares_event_t *event)
    176 {
    177   ares_evsys_kqueue_event_process(event, event->flags, 0);
    178 }
    179 
    180 static void ares_evsys_kqueue_event_mod(ares_event_t      *event,
    181                                         ares_event_flags_t new_flags)
    182 {
    183   ares_evsys_kqueue_event_process(event, event->flags, new_flags);
    184 }
    185 
    186 static size_t ares_evsys_kqueue_wait(ares_event_thread_t *e,
    187                                      unsigned long        timeout_ms)
    188 {
    189   struct kevent        events[8];
    190   size_t               nevents = sizeof(events) / sizeof(*events);
    191   ares_evsys_kqueue_t *kq      = e->ev_sys_data;
    192   int                  rv;
    193   size_t               i;
    194   struct timespec      ts;
    195   struct timespec     *timeout = NULL;
    196   size_t               cnt     = 0;
    197 
    198   if (timeout_ms != 0) {
    199     ts.tv_sec  = (time_t)timeout_ms / 1000;
    200     ts.tv_nsec = (timeout_ms % 1000) * 1000 * 1000;
    201     timeout    = &ts;
    202   }
    203 
    204   memset(events, 0, sizeof(events));
    205 
    206   rv = kevent(kq->kqueue_fd, kq->changelist, (int)kq->nchanges, events,
    207               (int)nevents, timeout);
    208   if (rv < 0) {
    209     return 0;
    210   }
    211 
    212   /* Changelist was consumed */
    213   kq->nchanges = 0;
    214   nevents      = (size_t)rv;
    215 
    216   for (i = 0; i < nevents; i++) {
    217     ares_event_t      *ev;
    218     ares_event_flags_t flags = 0;
    219 
    220     ev = ares_htable_asvp_get_direct(e->ev_sock_handles,
    221                                      (ares_socket_t)events[i].ident);
    222     if (ev == NULL || ev->cb == NULL) {
    223       continue;
    224     }
    225 
    226     cnt++;
    227 
    228     if (events[i].filter == EVFILT_READ ||
    229         events[i].flags & (EV_EOF | EV_ERROR)) {
    230       flags |= ARES_EVENT_FLAG_READ;
    231     } else {
    232       flags |= ARES_EVENT_FLAG_WRITE;
    233     }
    234 
    235     ev->cb(e, ev->fd, ev->data, flags);
    236   }
    237 
    238   return cnt;
    239 }
    240 
    241 const ares_event_sys_t ares_evsys_kqueue = { "kqueue",
    242                                              ares_evsys_kqueue_init,
    243                                              ares_evsys_kqueue_destroy,
    244                                              ares_evsys_kqueue_event_add,
    245                                              ares_evsys_kqueue_event_del,
    246                                              ares_evsys_kqueue_event_mod,
    247                                              ares_evsys_kqueue_wait };
    248 #endif