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 12, 2022
1 parent da240e9 commit 6883ef5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 17 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ $(SSL_STLIBNAME): $(SSL_OBJ)
$(SSL_OBJ): ssl.c hiredis.h read.h sds.h alloc.h async.h win32.h async_private.h
#################### SSL building rules end ####################

hv libhv.c:
$(CC) -O0 -ggdb3 -I. -o hvbin libhv.c alloc.c async.c dict.c hiredis.c net.c read.c sds.c sockcompat.c $(STLIBNAME) -lhv

# Binaries:
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) -I. $< -levent $(STLIBNAME) $(REAL_LDFLAGS)
Expand Down
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 6883ef5

Please sign in to comment.