Skip to content

Commit

Permalink
Extended timer support for our libhv adapter.
Browse files Browse the repository at this point in the history
Keep track of any timer we have set so we can just update it if the user
changes the timeout, rather than continuously adding new timers.

The semantics differ slightly from other adapters as libhv disallows
zero'd timers.
  • Loading branch information
michael-grunder committed Sep 13, 2022
1 parent d1cc536 commit f202b80
Showing 1 changed file with 56 additions and 17 deletions.
73 changes: 56 additions & 17 deletions adapters/libhv.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#include "../hiredis.h"
#include "../async.h"

typedef struct redisLibhvEvents {
hio_t *io;
htimer_t *timer;
} redisLibhvEvents;

static void redisLibhvHandleEvents(hio_t* io) {
redisAsyncContext* context = (redisAsyncContext*)hevent_userdata(io);
int events = hio_events(io);
Expand All @@ -18,29 +23,35 @@ static void redisLibhvHandleEvents(hio_t* io) {
}

static void redisLibhvAddRead(void *privdata) {
hio_t* io = (hio_t*)privdata;
hio_add(io, redisLibhvHandleEvents, HV_READ);
redisLibhvEvents* events = (redisLibhvEvents*)privdata;
hio_add(events->io, redisLibhvHandleEvents, HV_READ);
}

static void redisLibhvDelRead(void *privdata) {
hio_t* io = (hio_t*)privdata;
hio_del(io, HV_READ);
redisLibhvEvents* events = (redisLibhvEvents*)privdata;
hio_del(events->io, HV_READ);
}

static void redisLibhvAddWrite(void *privdata) {
hio_t* io = (hio_t*)privdata;
hio_add(io, redisLibhvHandleEvents, HV_WRITE);
redisLibhvEvents* events = (redisLibhvEvents*)privdata;
hio_add(events->io, redisLibhvHandleEvents, HV_WRITE);
}

static void redisLibhvDelWrite(void *privdata) {
hio_t* io = (hio_t*)privdata;
hio_del(io, HV_WRITE);
redisLibhvEvents* events = (redisLibhvEvents*)privdata;
hio_del(events->io, HV_WRITE);
}

static void redisLibhvCleanup(void *privdata) {
hio_t* io = (hio_t*)privdata;
hio_close(io);
hevent_set_userdata(io, NULL);
redisLibhvEvents* events = (redisLibhvEvents*)privdata;

if (events->timer)
htimer_del(events->timer);

hio_close(events->io);
hevent_set_userdata(events->io, NULL);

hi_free(events);
}

static void redisLibhvTimeout(htimer_t* timer) {
Expand All @@ -49,38 +60,66 @@ static void redisLibhvTimeout(htimer_t* timer) {
}

static void redisLibhvSetTimeout(void *privdata, struct timeval tv) {
hio_t* io = (hio_t*)privdata;
hloop_t* loop = hevent_loop(io);
htimer_t *timer;
redisLibhvEvents* events;
uint32_t millis;
hloop_t* loop;

events = (redisLibhvEvents*)privdata;
millis = tv.tv_sec * 1000 + tv.tv_usec / 1000;
timer = htimer_add(loop, redisLibhvTimeout, millis, 1);

hevent_set_userdata(timer, io);
/* Libhv disallows zero'd timers so handle that condition first */
if (millis == 0) {
if (events->timer) {
htimer_del(events->timer);
events->timer = NULL;
}

return;
}

/* Either create or reset an existing timer */
if (events->timer == NULL) {
loop = hevent_loop(events->io);
events->timer = htimer_add(loop, redisLibhvTimeout, millis, 1);
hevent_set_userdata(events->timer, events->io);
} else {
htimer_reset(events->timer, millis);
}
}

static int redisLibhvAttach(redisAsyncContext* ac, hloop_t* loop) {
redisContext *c = &(ac->c);
redisLibhvEvents *events;
hio_t* io = NULL;

if (ac->ev.data != NULL) {
return REDIS_ERR;
}

/* Create container struct to keep track of our io and any timer */
events = hi_malloc(sizeof(*events));
if (events == NULL) {
return REDIS_ERR;
}

io = hio_get(loop, c->fd);
if (io == NULL) {
hi_free(events);
return REDIS_ERR;
}

hevent_set_userdata(io, ac);

events->io = io;
events->timer = NULL;

ac->ev.addRead = redisLibhvAddRead;
ac->ev.delRead = redisLibhvDelRead;
ac->ev.addWrite = redisLibhvAddWrite;
ac->ev.delWrite = redisLibhvDelWrite;
ac->ev.cleanup = redisLibhvCleanup;
ac->ev.scheduleTimer = redisLibhvSetTimeout;
ac->ev.data = io;
ac->ev.data = events;

return REDIS_OK;
}
Expand Down

0 comments on commit f202b80

Please sign in to comment.