From eafc6f95bd7bd71374cc3ac8bb2b0f3d7c026e0b Mon Sep 17 00:00:00 2001 From: michael-grunder Date: Mon, 12 Sep 2022 15:53:30 -0700 Subject: [PATCH] Extended timer support for our libhv adapter. 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. --- adapters/libhv.h | 73 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/adapters/libhv.h b/adapters/libhv.h index 42430b127..418d6942f 100644 --- a/adapters/libhv.h +++ b/adapters/libhv.h @@ -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); @@ -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) { @@ -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; }