Edit

kc3-lang/kc3/event/event.c

Branch :

  • event/event.c
  • /* kc3
     * Copyright from 2022 to 2025 kmx.io <contact@kmx.io>
     *
     * Permission is hereby granted to use this software granted the above
     * copyright notice and this permission paragraph are included in all
     * copies and substantial portions of this software.
     *
     * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
     * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
     * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
     * THIS SOFTWARE.
     */
    #include <event2/event.h>
    #include <libkc3/kc3.h>
    #include <signal.h>
    #include "event.h"
    
    s32 kc3_event_add (struct event **ev, s_time *time)
    {
      struct timeval tv;
      if (! time->tv_sec && ! time->tv_nsec)
        return event_add(*ev, NULL);
      tv.tv_sec = time->tv_sec;
      tv.tv_usec = time->tv_nsec / 1000;
      return event_add(*ev, &tv);
    }
    
    s32 kc3_event_del (struct event **ev)
    {
      return event_del(*ev);
    }
    
    /* kc3_event_callback
         expects a tag of the form
         {fn ((S32) fd, (List) events, (Ptr) ev, (Tag) Arg) {void},
          arg} */
    #if defined(WIN64)
    static void kc3_event_callback (long long fd, short events, void *tag_tuple)
    #else
    static void kc3_event_callback (int fd, short events, void *tag_tuple)
    #endif
    {
      s_tag  *arg;
      s_list *arguments;
      p_callable callable;
      struct event *ev;
      s_list       *events_list;
      s_tag *tag;
      s_tag tmp;
      tag = tag_tuple;
      if (tag->type != TAG_TUPLE) {
        err_puts("kc3_event_callback: invalid arg: not a Tuple");
        assert(! "kc3_event_callback: invalid arg: not a Tuple");
        abort();
      }
      if (tag->data.tuple.count != 3) {
        err_puts("kc3_event_callback: invalid arg: tuple size != 3");
        assert(! "kc3_event_callback: invalid arg: tuple size != 3");
        abort();
      }
      if (tag->data.tuple.tag[0].type != TAG_PCALLABLE) {
        err_puts("kc3_event_callback: invalid arg: not a Callable"
                 " (Cfn or Fn)");
        assert(!("kc3_event_callback: invalid arg: not a Callable"
                 " (Cfn or Fn)"));
        abort();
      }
      if (! (callable = tag->data.tuple.tag[0].data.pcallable)) {
        err_puts("kc3_event_callback: invalid arg: ! callable");
        assert(! "kc3_event_callback: invalid arg: ! callable");
        abort();
      }
      if (callable->type == CALLABLE_VOID) {
        err_puts("kc3_event_callback: invalid arg: CALLABLE_VOID");
        assert(! "kc3_event_callback: invalid arg: CALLABLE_VOID");
        abort();
      }
      if (tag->data.tuple.tag[1].type != TAG_PTR) {
        err_puts("kc3_event_callback: invalid arg 2: not a Ptr");
        assert(! "kc3_event_callback: invalid arg 2: not a Ptr");
        abort();
      }
      ev = tag->data.tuple.tag[1].data.ptr.p;
      arg = tag->data.tuple.tag + 2;
      events_list = NULL;
      if (events & EV_PERSIST)
        events_list = list_new_sym(&g_sym_persist, events_list);
      if (events & EV_WRITE)
        events_list = list_new_sym(&g_sym_write, events_list);
      if (events & EV_READ)
        events_list = list_new_sym(&g_sym_read, events_list);
      if (events & EV_SIGNAL)
        events_list = list_new_sym(&g_sym_signal, events_list);
      if (events & EV_TIMEOUT)
        events_list = list_new_sym(&g_sym_timeout, events_list);
      arguments = list_new_s32(fd, list_new_list
                               (events_list, list_new_ptr
                                (ev, list_new_tag_copy
                                 (arg, NULL))));
      if (! eval_callable_call(callable, arguments, &tmp)) {
        err_puts("kc3_event_callback: callback failed");
        assert(! "kc3_event_callback: callback failed");
        abort();
      }
      tag_clean(&tmp);
    }
    
    s32 kc3_event_base_dispatch (struct event_base **eb)
    {
      return event_base_dispatch(*eb);
    }
    
    struct event_base * kc3_event_base_new (void)
    {
      return event_base_new();
    }
    
    struct event * kc3_event_new (struct event_base **event_base, s32 fd,
                                  const s_list * const *events,
                                  p_callable *callback, s_tag *arg)
    {
      const s_list *e;
      struct event *ev;
      s16 events_s16;
      s_tag *tag;
      events_s16 = 0;
      e = *events;
      while (e) {
        if (e->tag.type != TAG_SYM)
          goto invalid_event_list;
        if (e->tag.data.sym == &g_sym_read)
          events_s16 |= EV_READ;
        else if (e->tag.data.sym == &g_sym_write)
          events_s16 |= EV_WRITE;
        else if (e->tag.data.sym == &g_sym_persist)
          events_s16 |= EV_PERSIST;
        else
          goto invalid_event_list;
        e = list_next(e);
      }
      tag = tag_new_tuple(3);
      ev = event_new(*event_base, fd, events_s16, kc3_event_callback, tag);
      if (! ev) {
        tag_delete(tag);
        err_puts("kc3_event_new: event_new");
        assert(! "kc3_event_new: event_new");
        return NULL;
      }
      tag_init_pcallable_copy(tag->data.tuple.tag, callback);
      tag_init_copy(tag->data.tuple.tag + 2, arg);
      tag_init_ptr(tag->data.tuple.tag + 1, ev);
      return ev;
     invalid_event_list:
      err_write_1("kc3_event_new: invalid event list: ");
      err_inspect_list(*events);
      assert(! "kc3_event_new: invalid event list");
      return NULL;
    }
    
    s_str * kc3_event_version (s_str *dest)
    {
      return str_init_1(dest, NULL, event_get_version());
    }