/* * Copyright (c) 2009-2011, Salvatore Sanfilippo * * SPDX-FileCopyrightText: 2024 Hiredict Contributors * SPDX-FileCopyrightText: 2024 Salvatore Sanfilippo * * SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: LGPL-3.0-or-later * */ #ifndef HIREDICT_LIBSDEVENT_H #define HIREDICT_LIBSDEVENT_H #include #include "../hiredict.h" #include "../async.h" #define REDICT_LIBSDEVENT_DELETED 0x01 #define REDICT_LIBSDEVENT_ENTERED 0x02 typedef struct redictLibsdeventEvents { redictAsyncContext *context; struct sd_event *event; struct sd_event_source *fdSource; struct sd_event_source *timerSource; int fd; short flags; short state; } redictLibsdeventEvents; static void redictLibsdeventDestroy(redictLibsdeventEvents *e) { if (e->fdSource) { e->fdSource = sd_event_source_disable_unref(e->fdSource); } if (e->timerSource) { e->timerSource = sd_event_source_disable_unref(e->timerSource); } sd_event_unref(e->event); hi_free(e); } static int redictLibsdeventTimeoutHandler(sd_event_source *s, uint64_t usec, void *userdata) { ((void)s); ((void)usec); redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; redictAsyncHandleTimeout(e->context); return 0; } static int redictLibsdeventHandler(sd_event_source *s, int fd, uint32_t event, void *userdata) { ((void)s); ((void)fd); redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; e->state |= REDICT_LIBSDEVENT_ENTERED; #define CHECK_DELETED() if (e->state & REDICT_LIBSDEVENT_DELETED) {\ redictLibsdeventDestroy(e);\ return 0; \ } if ((event & EPOLLIN) && e->context && (e->state & REDICT_LIBSDEVENT_DELETED) == 0) { redictAsyncHandleRead(e->context); CHECK_DELETED(); } if ((event & EPOLLOUT) && e->context && (e->state & REDICT_LIBSDEVENT_DELETED) == 0) { redictAsyncHandleWrite(e->context); CHECK_DELETED(); } e->state &= ~REDICT_LIBSDEVENT_ENTERED; #undef CHECK_DELETED return 0; } static void redictLibsdeventAddRead(void *userdata) { redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; if (e->flags & EPOLLIN) { return; } e->flags |= EPOLLIN; if (e->flags & EPOLLOUT) { sd_event_source_set_io_events(e->fdSource, e->flags); } else { sd_event_add_io(e->event, &e->fdSource, e->fd, e->flags, redictLibsdeventHandler, e); } } static void redictLibsdeventDelRead(void *userdata) { redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; e->flags &= ~EPOLLIN; if (e->flags) { sd_event_source_set_io_events(e->fdSource, e->flags); } else { e->fdSource = sd_event_source_disable_unref(e->fdSource); } } static void redictLibsdeventAddWrite(void *userdata) { redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; if (e->flags & EPOLLOUT) { return; } e->flags |= EPOLLOUT; if (e->flags & EPOLLIN) { sd_event_source_set_io_events(e->fdSource, e->flags); } else { sd_event_add_io(e->event, &e->fdSource, e->fd, e->flags, redictLibsdeventHandler, e); } } static void redictLibsdeventDelWrite(void *userdata) { redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; e->flags &= ~EPOLLOUT; if (e->flags) { sd_event_source_set_io_events(e->fdSource, e->flags); } else { e->fdSource = sd_event_source_disable_unref(e->fdSource); } } static void redictLibsdeventCleanup(void *userdata) { redictLibsdeventEvents *e = (redictLibsdeventEvents*)userdata; if (!e) { return; } if (e->state & REDICT_LIBSDEVENT_ENTERED) { e->state |= REDICT_LIBSDEVENT_DELETED; } else { redictLibsdeventDestroy(e); } } static void redictLibsdeventSetTimeout(void *userdata, struct timeval tv) { redictLibsdeventEvents *e = (redictLibsdeventEvents *)userdata; uint64_t usec = tv.tv_sec * 1000000 + tv.tv_usec; if (!e->timerSource) { sd_event_add_time_relative(e->event, &e->timerSource, CLOCK_MONOTONIC, usec, 1, redictLibsdeventTimeoutHandler, e); } else { sd_event_source_set_time_relative(e->timerSource, usec); } } static int redictLibsdeventAttach(redictAsyncContext *ac, struct sd_event *event) { redictContext *c = &(ac->c); redictLibsdeventEvents *e; /* Nothing should be attached when something is already attached */ if (ac->ev.data != NULL) return REDICT_ERR; /* Create container for context and r/w events */ e = (redictLibsdeventEvents*)hi_calloc(1, sizeof(*e)); if (e == NULL) return REDICT_ERR; /* Initialize and increase event refcount */ e->context = ac; e->event = event; e->fd = c->fd; sd_event_ref(event); /* Register functions to start/stop listening for events */ ac->ev.addRead = redictLibsdeventAddRead; ac->ev.delRead = redictLibsdeventDelRead; ac->ev.addWrite = redictLibsdeventAddWrite; ac->ev.delWrite = redictLibsdeventDelWrite; ac->ev.cleanup = redictLibsdeventCleanup; ac->ev.scheduleTimer = redictLibsdeventSetTimeout; ac->ev.data = e; return REDICT_OK; } #endif