diff options
Diffstat (limited to 'deps/hiredis/adapters')
-rw-r--r-- | deps/hiredis/adapters/ae.h | 130 | ||||
-rw-r--r-- | deps/hiredis/adapters/glib.h | 156 | ||||
-rw-r--r-- | deps/hiredis/adapters/ivykis.h | 84 | ||||
-rw-r--r-- | deps/hiredis/adapters/libev.h | 188 | ||||
-rw-r--r-- | deps/hiredis/adapters/libevent.h | 175 | ||||
-rw-r--r-- | deps/hiredis/adapters/libhv.h | 123 | ||||
-rw-r--r-- | deps/hiredis/adapters/libsdevent.h | 177 | ||||
-rw-r--r-- | deps/hiredis/adapters/libuv.h | 171 | ||||
-rw-r--r-- | deps/hiredis/adapters/macosx.h | 115 | ||||
-rw-r--r-- | deps/hiredis/adapters/poll.h | 197 | ||||
-rw-r--r-- | deps/hiredis/adapters/qt.h | 135 | ||||
-rw-r--r-- | deps/hiredis/adapters/redismoduleapi.h | 144 |
12 files changed, 1795 insertions, 0 deletions
diff --git a/deps/hiredis/adapters/ae.h b/deps/hiredis/adapters/ae.h new file mode 100644 index 0000000..660d82e --- /dev/null +++ b/deps/hiredis/adapters/ae.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_AE_H__ +#define __HIREDIS_AE_H__ +#include <sys/types.h> +#include <ae.h> +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisAeEvents { + redisAsyncContext *context; + aeEventLoop *loop; + int fd; + int reading, writing; +} redisAeEvents; + +static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { + ((void)el); ((void)fd); ((void)mask); + + redisAeEvents *e = (redisAeEvents*)privdata; + redisAsyncHandleRead(e->context); +} + +static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { + ((void)el); ((void)fd); ((void)mask); + + redisAeEvents *e = (redisAeEvents*)privdata; + redisAsyncHandleWrite(e->context); +} + +static void redisAeAddRead(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (!e->reading) { + e->reading = 1; + aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); + } +} + +static void redisAeDelRead(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (e->reading) { + e->reading = 0; + aeDeleteFileEvent(loop,e->fd,AE_READABLE); + } +} + +static void redisAeAddWrite(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (!e->writing) { + e->writing = 1; + aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); + } +} + +static void redisAeDelWrite(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + aeEventLoop *loop = e->loop; + if (e->writing) { + e->writing = 0; + aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); + } +} + +static void redisAeCleanup(void *privdata) { + redisAeEvents *e = (redisAeEvents*)privdata; + redisAeDelRead(privdata); + redisAeDelWrite(privdata); + hi_free(e); +} + +static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisAeEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisAeEvents*)hi_malloc(sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + e->context = ac; + e->loop = loop; + e->fd = c->fd; + e->reading = e->writing = 0; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisAeAddRead; + ac->ev.delRead = redisAeDelRead; + ac->ev.addWrite = redisAeAddWrite; + ac->ev.delWrite = redisAeDelWrite; + ac->ev.cleanup = redisAeCleanup; + ac->ev.data = e; + + return REDIS_OK; +} +#endif diff --git a/deps/hiredis/adapters/glib.h b/deps/hiredis/adapters/glib.h new file mode 100644 index 0000000..ad59dd1 --- /dev/null +++ b/deps/hiredis/adapters/glib.h @@ -0,0 +1,156 @@ +#ifndef __HIREDIS_GLIB_H__ +#define __HIREDIS_GLIB_H__ + +#include <glib.h> + +#include "../hiredis.h" +#include "../async.h" + +typedef struct +{ + GSource source; + redisAsyncContext *ac; + GPollFD poll_fd; +} RedisSource; + +static void +redis_source_add_read (gpointer data) +{ + RedisSource *source = (RedisSource *)data; + g_return_if_fail(source); + source->poll_fd.events |= G_IO_IN; + g_main_context_wakeup(g_source_get_context((GSource *)data)); +} + +static void +redis_source_del_read (gpointer data) +{ + RedisSource *source = (RedisSource *)data; + g_return_if_fail(source); + source->poll_fd.events &= ~G_IO_IN; + g_main_context_wakeup(g_source_get_context((GSource *)data)); +} + +static void +redis_source_add_write (gpointer data) +{ + RedisSource *source = (RedisSource *)data; + g_return_if_fail(source); + source->poll_fd.events |= G_IO_OUT; + g_main_context_wakeup(g_source_get_context((GSource *)data)); +} + +static void +redis_source_del_write (gpointer data) +{ + RedisSource *source = (RedisSource *)data; + g_return_if_fail(source); + source->poll_fd.events &= ~G_IO_OUT; + g_main_context_wakeup(g_source_get_context((GSource *)data)); +} + +static void +redis_source_cleanup (gpointer data) +{ + RedisSource *source = (RedisSource *)data; + + g_return_if_fail(source); + + redis_source_del_read(source); + redis_source_del_write(source); + /* + * It is not our responsibility to remove ourself from the + * current main loop. However, we will remove the GPollFD. + */ + if (source->poll_fd.fd >= 0) { + g_source_remove_poll((GSource *)data, &source->poll_fd); + source->poll_fd.fd = -1; + } +} + +static gboolean +redis_source_prepare (GSource *source, + gint *timeout_) +{ + RedisSource *redis = (RedisSource *)source; + *timeout_ = -1; + return !!(redis->poll_fd.events & redis->poll_fd.revents); +} + +static gboolean +redis_source_check (GSource *source) +{ + RedisSource *redis = (RedisSource *)source; + return !!(redis->poll_fd.events & redis->poll_fd.revents); +} + +static gboolean +redis_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + RedisSource *redis = (RedisSource *)source; + + if ((redis->poll_fd.revents & G_IO_OUT)) { + redisAsyncHandleWrite(redis->ac); + redis->poll_fd.revents &= ~G_IO_OUT; + } + + if ((redis->poll_fd.revents & G_IO_IN)) { + redisAsyncHandleRead(redis->ac); + redis->poll_fd.revents &= ~G_IO_IN; + } + + if (callback) { + return callback(user_data); + } + + return TRUE; +} + +static void +redis_source_finalize (GSource *source) +{ + RedisSource *redis = (RedisSource *)source; + + if (redis->poll_fd.fd >= 0) { + g_source_remove_poll(source, &redis->poll_fd); + redis->poll_fd.fd = -1; + } +} + +static GSource * +redis_source_new (redisAsyncContext *ac) +{ + static GSourceFuncs source_funcs = { + .prepare = redis_source_prepare, + .check = redis_source_check, + .dispatch = redis_source_dispatch, + .finalize = redis_source_finalize, + }; + redisContext *c = &ac->c; + RedisSource *source; + + g_return_val_if_fail(ac != NULL, NULL); + + source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); + if (source == NULL) + return NULL; + + source->ac = ac; + source->poll_fd.fd = c->fd; + source->poll_fd.events = 0; + source->poll_fd.revents = 0; + g_source_add_poll((GSource *)source, &source->poll_fd); + + ac->ev.addRead = redis_source_add_read; + ac->ev.delRead = redis_source_del_read; + ac->ev.addWrite = redis_source_add_write; + ac->ev.delWrite = redis_source_del_write; + ac->ev.cleanup = redis_source_cleanup; + ac->ev.data = source; + + return (GSource *)source; +} + +#endif /* __HIREDIS_GLIB_H__ */ diff --git a/deps/hiredis/adapters/ivykis.h b/deps/hiredis/adapters/ivykis.h new file mode 100644 index 0000000..179f6ab --- /dev/null +++ b/deps/hiredis/adapters/ivykis.h @@ -0,0 +1,84 @@ +#ifndef __HIREDIS_IVYKIS_H__ +#define __HIREDIS_IVYKIS_H__ +#include <iv.h> +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisIvykisEvents { + redisAsyncContext *context; + struct iv_fd fd; +} redisIvykisEvents; + +static void redisIvykisReadEvent(void *arg) { + redisAsyncContext *context = (redisAsyncContext *)arg; + redisAsyncHandleRead(context); +} + +static void redisIvykisWriteEvent(void *arg) { + redisAsyncContext *context = (redisAsyncContext *)arg; + redisAsyncHandleWrite(context); +} + +static void redisIvykisAddRead(void *privdata) { + redisIvykisEvents *e = (redisIvykisEvents*)privdata; + iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent); +} + +static void redisIvykisDelRead(void *privdata) { + redisIvykisEvents *e = (redisIvykisEvents*)privdata; + iv_fd_set_handler_in(&e->fd, NULL); +} + +static void redisIvykisAddWrite(void *privdata) { + redisIvykisEvents *e = (redisIvykisEvents*)privdata; + iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent); +} + +static void redisIvykisDelWrite(void *privdata) { + redisIvykisEvents *e = (redisIvykisEvents*)privdata; + iv_fd_set_handler_out(&e->fd, NULL); +} + +static void redisIvykisCleanup(void *privdata) { + redisIvykisEvents *e = (redisIvykisEvents*)privdata; + + iv_fd_unregister(&e->fd); + hi_free(e); +} + +static int redisIvykisAttach(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisIvykisEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisIvykisEvents*)hi_malloc(sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + e->context = ac; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisIvykisAddRead; + ac->ev.delRead = redisIvykisDelRead; + ac->ev.addWrite = redisIvykisAddWrite; + ac->ev.delWrite = redisIvykisDelWrite; + ac->ev.cleanup = redisIvykisCleanup; + ac->ev.data = e; + + /* Initialize and install read/write events */ + IV_FD_INIT(&e->fd); + e->fd.fd = c->fd; + e->fd.handler_in = redisIvykisReadEvent; + e->fd.handler_out = redisIvykisWriteEvent; + e->fd.handler_err = NULL; + e->fd.cookie = e->context; + + iv_fd_register(&e->fd); + + return REDIS_OK; +} +#endif diff --git a/deps/hiredis/adapters/libev.h b/deps/hiredis/adapters/libev.h new file mode 100644 index 0000000..c59d3da --- /dev/null +++ b/deps/hiredis/adapters/libev.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_LIBEV_H__ +#define __HIREDIS_LIBEV_H__ +#include <stdlib.h> +#include <sys/types.h> +#include <ev.h> +#include "../hiredis.h" +#include "../async.h" + +typedef struct redisLibevEvents { + redisAsyncContext *context; + struct ev_loop *loop; + int reading, writing; + ev_io rev, wev; + ev_timer timer; +} redisLibevEvents; + +static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { +#if EV_MULTIPLICITY + ((void)EV_A); +#endif + ((void)revents); + + redisLibevEvents *e = (redisLibevEvents*)watcher->data; + redisAsyncHandleRead(e->context); +} + +static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { +#if EV_MULTIPLICITY + ((void)EV_A); +#endif + ((void)revents); + + redisLibevEvents *e = (redisLibevEvents*)watcher->data; + redisAsyncHandleWrite(e->context); +} + +static void redisLibevAddRead(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; +#if EV_MULTIPLICITY + struct ev_loop *loop = e->loop; +#endif + if (!e->reading) { + e->reading = 1; + ev_io_start(EV_A_ &e->rev); + } +} + +static void redisLibevDelRead(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; +#if EV_MULTIPLICITY + struct ev_loop *loop = e->loop; +#endif + if (e->reading) { + e->reading = 0; + ev_io_stop(EV_A_ &e->rev); + } +} + +static void redisLibevAddWrite(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; +#if EV_MULTIPLICITY + struct ev_loop *loop = e->loop; +#endif + if (!e->writing) { + e->writing = 1; + ev_io_start(EV_A_ &e->wev); + } +} + +static void redisLibevDelWrite(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; +#if EV_MULTIPLICITY + struct ev_loop *loop = e->loop; +#endif + if (e->writing) { + e->writing = 0; + ev_io_stop(EV_A_ &e->wev); + } +} + +static void redisLibevStopTimer(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; +#if EV_MULTIPLICITY + struct ev_loop *loop = e->loop; +#endif + ev_timer_stop(EV_A_ &e->timer); +} + +static void redisLibevCleanup(void *privdata) { + redisLibevEvents *e = (redisLibevEvents*)privdata; + redisLibevDelRead(privdata); + redisLibevDelWrite(privdata); + redisLibevStopTimer(privdata); + hi_free(e); +} + +static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) { +#if EV_MULTIPLICITY + ((void)EV_A); +#endif + ((void)revents); + redisLibevEvents *e = (redisLibevEvents*)timer->data; + redisAsyncHandleTimeout(e->context); +} + +static void redisLibevSetTimeout(void *privdata, struct timeval tv) { + redisLibevEvents *e = (redisLibevEvents*)privdata; +#if EV_MULTIPLICITY + struct ev_loop *loop = e->loop; +#endif + + if (!ev_is_active(&e->timer)) { + ev_init(&e->timer, redisLibevTimeout); + e->timer.data = e; + } + + e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00; + ev_timer_again(EV_A_ &e->timer); +} + +static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisLibevEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibevEvents*)hi_calloc(1, sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + e->context = ac; +#if EV_MULTIPLICITY + e->loop = EV_A; +#else + e->loop = NULL; +#endif + e->rev.data = e; + e->wev.data = e; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibevAddRead; + ac->ev.delRead = redisLibevDelRead; + ac->ev.addWrite = redisLibevAddWrite; + ac->ev.delWrite = redisLibevDelWrite; + ac->ev.cleanup = redisLibevCleanup; + ac->ev.scheduleTimer = redisLibevSetTimeout; + ac->ev.data = e; + + /* Initialize read/write events */ + ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); + ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); + return REDIS_OK; +} + +#endif diff --git a/deps/hiredis/adapters/libevent.h b/deps/hiredis/adapters/libevent.h new file mode 100644 index 0000000..73bb8ed --- /dev/null +++ b/deps/hiredis/adapters/libevent.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __HIREDIS_LIBEVENT_H__ +#define __HIREDIS_LIBEVENT_H__ +#include <event2/event.h> +#include "../hiredis.h" +#include "../async.h" + +#define REDIS_LIBEVENT_DELETED 0x01 +#define REDIS_LIBEVENT_ENTERED 0x02 + +typedef struct redisLibeventEvents { + redisAsyncContext *context; + struct event *ev; + struct event_base *base; + struct timeval tv; + short flags; + short state; +} redisLibeventEvents; + +static void redisLibeventDestroy(redisLibeventEvents *e) { + hi_free(e); +} + +static void redisLibeventHandler(evutil_socket_t fd, short event, void *arg) { + ((void)fd); + redisLibeventEvents *e = (redisLibeventEvents*)arg; + e->state |= REDIS_LIBEVENT_ENTERED; + + #define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\ + redisLibeventDestroy(e);\ + return; \ + } + + if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) { + redisAsyncHandleTimeout(e->context); + CHECK_DELETED(); + } + + if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { + redisAsyncHandleRead(e->context); + CHECK_DELETED(); + } + + if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) { + redisAsyncHandleWrite(e->context); + CHECK_DELETED(); + } + + e->state &= ~REDIS_LIBEVENT_ENTERED; + #undef CHECK_DELETED +} + +static void redisLibeventUpdate(void *privdata, short flag, int isRemove) { + redisLibeventEvents *e = (redisLibeventEvents *)privdata; + const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL; + + if (isRemove) { + if ((e->flags & flag) == 0) { + return; + } else { + e->flags &= ~flag; + } + } else { + if (e->flags & flag) { + return; + } else { + e->flags |= flag; + } + } + + event_del(e->ev); + event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST, + redisLibeventHandler, privdata); + event_add(e->ev, tv); +} + +static void redisLibeventAddRead(void *privdata) { + redisLibeventUpdate(privdata, EV_READ, 0); +} + +static void redisLibeventDelRead(void *privdata) { + redisLibeventUpdate(privdata, EV_READ, 1); +} + +static void redisLibeventAddWrite(void *privdata) { + redisLibeventUpdate(privdata, EV_WRITE, 0); +} + +static void redisLibeventDelWrite(void *privdata) { + redisLibeventUpdate(privdata, EV_WRITE, 1); +} + +static void redisLibeventCleanup(void *privdata) { + redisLibeventEvents *e = (redisLibeventEvents*)privdata; + if (!e) { + return; + } + event_del(e->ev); + event_free(e->ev); + e->ev = NULL; + + if (e->state & REDIS_LIBEVENT_ENTERED) { + e->state |= REDIS_LIBEVENT_DELETED; + } else { + redisLibeventDestroy(e); + } +} + +static void redisLibeventSetTimeout(void *privdata, struct timeval tv) { + redisLibeventEvents *e = (redisLibeventEvents *)privdata; + short flags = e->flags; + e->flags = 0; + e->tv = tv; + redisLibeventUpdate(e, flags, 0); +} + +static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { + redisContext *c = &(ac->c); + redisLibeventEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + e->context = ac; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisLibeventAddRead; + ac->ev.delRead = redisLibeventDelRead; + ac->ev.addWrite = redisLibeventAddWrite; + ac->ev.delWrite = redisLibeventDelWrite; + ac->ev.cleanup = redisLibeventCleanup; + ac->ev.scheduleTimer = redisLibeventSetTimeout; + ac->ev.data = e; + + /* Initialize and install read/write events */ + e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e); + e->base = base; + return REDIS_OK; +} +#endif diff --git a/deps/hiredis/adapters/libhv.h b/deps/hiredis/adapters/libhv.h new file mode 100644 index 0000000..3b54c70 --- /dev/null +++ b/deps/hiredis/adapters/libhv.h @@ -0,0 +1,123 @@ +#ifndef __HIREDIS_LIBHV_H__ +#define __HIREDIS_LIBHV_H__ + +#include <hv/hloop.h> +#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); + int revents = hio_revents(io); + if (context && (events & HV_READ) && (revents & HV_READ)) { + redisAsyncHandleRead(context); + } + if (context && (events & HV_WRITE) && (revents & HV_WRITE)) { + redisAsyncHandleWrite(context); + } +} + +static void redisLibhvAddRead(void *privdata) { + redisLibhvEvents* events = (redisLibhvEvents*)privdata; + hio_add(events->io, redisLibhvHandleEvents, HV_READ); +} + +static void redisLibhvDelRead(void *privdata) { + redisLibhvEvents* events = (redisLibhvEvents*)privdata; + hio_del(events->io, HV_READ); +} + +static void redisLibhvAddWrite(void *privdata) { + redisLibhvEvents* events = (redisLibhvEvents*)privdata; + hio_add(events->io, redisLibhvHandleEvents, HV_WRITE); +} + +static void redisLibhvDelWrite(void *privdata) { + redisLibhvEvents* events = (redisLibhvEvents*)privdata; + hio_del(events->io, HV_WRITE); +} + +static void redisLibhvCleanup(void *privdata) { + 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) { + hio_t* io = (hio_t*)hevent_userdata(timer); + redisAsyncHandleTimeout((redisAsyncContext*)hevent_userdata(io)); +} + +static void redisLibhvSetTimeout(void *privdata, struct timeval tv) { + redisLibhvEvents* events; + uint32_t millis; + hloop_t* loop; + + events = (redisLibhvEvents*)privdata; + millis = tv.tv_sec * 1000 + tv.tv_usec / 1000; + + if (millis == 0) { + /* Libhv disallows zero'd timers so treat this as a delete or NO OP */ + if (events->timer) { + htimer_del(events->timer); + events->timer = NULL; + } + } else if (events->timer == NULL) { + /* Add new timer */ + loop = hevent_loop(events->io); + events->timer = htimer_add(loop, redisLibhvTimeout, millis, 1); + hevent_set_userdata(events->timer, events->io); + } else { + /* Update existing timer */ + 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 = (redisLibhvEvents*)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 = events; + + return REDIS_OK; +} +#endif diff --git a/deps/hiredis/adapters/libsdevent.h b/deps/hiredis/adapters/libsdevent.h new file mode 100644 index 0000000..1268ed9 --- /dev/null +++ b/deps/hiredis/adapters/libsdevent.h @@ -0,0 +1,177 @@ +#ifndef HIREDIS_LIBSDEVENT_H +#define HIREDIS_LIBSDEVENT_H +#include <systemd/sd-event.h> +#include "../hiredis.h" +#include "../async.h" + +#define REDIS_LIBSDEVENT_DELETED 0x01 +#define REDIS_LIBSDEVENT_ENTERED 0x02 + +typedef struct redisLibsdeventEvents { + redisAsyncContext *context; + struct sd_event *event; + struct sd_event_source *fdSource; + struct sd_event_source *timerSource; + int fd; + short flags; + short state; +} redisLibsdeventEvents; + +static void redisLibsdeventDestroy(redisLibsdeventEvents *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 redisLibsdeventTimeoutHandler(sd_event_source *s, uint64_t usec, void *userdata) { + ((void)s); + ((void)usec); + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + redisAsyncHandleTimeout(e->context); + return 0; +} + +static int redisLibsdeventHandler(sd_event_source *s, int fd, uint32_t event, void *userdata) { + ((void)s); + ((void)fd); + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + e->state |= REDIS_LIBSDEVENT_ENTERED; + +#define CHECK_DELETED() if (e->state & REDIS_LIBSDEVENT_DELETED) {\ + redisLibsdeventDestroy(e);\ + return 0; \ + } + + if ((event & EPOLLIN) && e->context && (e->state & REDIS_LIBSDEVENT_DELETED) == 0) { + redisAsyncHandleRead(e->context); + CHECK_DELETED(); + } + + if ((event & EPOLLOUT) && e->context && (e->state & REDIS_LIBSDEVENT_DELETED) == 0) { + redisAsyncHandleWrite(e->context); + CHECK_DELETED(); + } + + e->state &= ~REDIS_LIBSDEVENT_ENTERED; +#undef CHECK_DELETED + + return 0; +} + +static void redisLibsdeventAddRead(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)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, redisLibsdeventHandler, e); + } +} + +static void redisLibsdeventDelRead(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)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 redisLibsdeventAddWrite(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)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, redisLibsdeventHandler, e); + } +} + +static void redisLibsdeventDelWrite(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)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 redisLibsdeventCleanup(void *userdata) { + redisLibsdeventEvents *e = (redisLibsdeventEvents*)userdata; + + if (!e) { + return; + } + + if (e->state & REDIS_LIBSDEVENT_ENTERED) { + e->state |= REDIS_LIBSDEVENT_DELETED; + } else { + redisLibsdeventDestroy(e); + } +} + +static void redisLibsdeventSetTimeout(void *userdata, struct timeval tv) { + redisLibsdeventEvents *e = (redisLibsdeventEvents *)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, redisLibsdeventTimeoutHandler, e); + } else { + sd_event_source_set_time_relative(e->timerSource, usec); + } +} + +static int redisLibsdeventAttach(redisAsyncContext *ac, struct sd_event *event) { + redisContext *c = &(ac->c); + redisLibsdeventEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisLibsdeventEvents*)hi_calloc(1, sizeof(*e)); + if (e == NULL) + return REDIS_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 = redisLibsdeventAddRead; + ac->ev.delRead = redisLibsdeventDelRead; + ac->ev.addWrite = redisLibsdeventAddWrite; + ac->ev.delWrite = redisLibsdeventDelWrite; + ac->ev.cleanup = redisLibsdeventCleanup; + ac->ev.scheduleTimer = redisLibsdeventSetTimeout; + ac->ev.data = e; + + return REDIS_OK; +} +#endif diff --git a/deps/hiredis/adapters/libuv.h b/deps/hiredis/adapters/libuv.h new file mode 100644 index 0000000..268edab --- /dev/null +++ b/deps/hiredis/adapters/libuv.h @@ -0,0 +1,171 @@ +#ifndef __HIREDIS_LIBUV_H__ +#define __HIREDIS_LIBUV_H__ +#include <stdlib.h> +#include <uv.h> +#include "../hiredis.h" +#include "../async.h" +#include <string.h> + +typedef struct redisLibuvEvents { + redisAsyncContext* context; + uv_poll_t handle; + uv_timer_t timer; + int events; +} redisLibuvEvents; + + +static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + int ev = (status ? p->events : events); + + if (p->context != NULL && (ev & UV_READABLE)) { + redisAsyncHandleRead(p->context); + } + if (p->context != NULL && (ev & UV_WRITABLE)) { + redisAsyncHandleWrite(p->context); + } +} + + +static void redisLibuvAddRead(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + if (p->events & UV_READABLE) { + return; + } + + p->events |= UV_READABLE; + + uv_poll_start(&p->handle, p->events, redisLibuvPoll); +} + + +static void redisLibuvDelRead(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events &= ~UV_READABLE; + + if (p->events) { + uv_poll_start(&p->handle, p->events, redisLibuvPoll); + } else { + uv_poll_stop(&p->handle); + } +} + + +static void redisLibuvAddWrite(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + if (p->events & UV_WRITABLE) { + return; + } + + p->events |= UV_WRITABLE; + + uv_poll_start(&p->handle, p->events, redisLibuvPoll); +} + + +static void redisLibuvDelWrite(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->events &= ~UV_WRITABLE; + + if (p->events) { + uv_poll_start(&p->handle, p->events, redisLibuvPoll); + } else { + uv_poll_stop(&p->handle); + } +} + +static void on_timer_close(uv_handle_t *handle) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + p->timer.data = NULL; + if (!p->handle.data) { + // both timer and handle are closed + hi_free(p); + } + // else, wait for `on_handle_close` +} + +static void on_handle_close(uv_handle_t *handle) { + redisLibuvEvents* p = (redisLibuvEvents*)handle->data; + p->handle.data = NULL; + if (!p->timer.data) { + // timer never started, or timer already destroyed + hi_free(p); + } + // else, wait for `on_timer_close` +} + +// libuv removed `status` parameter since v0.11.23 +// see: https://github.com/libuv/libuv/blob/v0.11.23/include/uv.h +#if (UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR < 11) || \ + (UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR == 11 && UV_VERSION_PATCH < 23) +static void redisLibuvTimeout(uv_timer_t *timer, int status) { + (void)status; // unused +#else +static void redisLibuvTimeout(uv_timer_t *timer) { +#endif + redisLibuvEvents *e = (redisLibuvEvents*)timer->data; + redisAsyncHandleTimeout(e->context); +} + +static void redisLibuvSetTimeout(void *privdata, struct timeval tv) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + uint64_t millsec = tv.tv_sec * 1000 + tv.tv_usec / 1000.0; + if (!p->timer.data) { + // timer is uninitialized + if (uv_timer_init(p->handle.loop, &p->timer) != 0) { + return; + } + p->timer.data = p; + } + // updates the timeout if the timer has already started + // or start the timer + uv_timer_start(&p->timer, redisLibuvTimeout, millsec, 0); +} + +static void redisLibuvCleanup(void *privdata) { + redisLibuvEvents* p = (redisLibuvEvents*)privdata; + + p->context = NULL; // indicate that context might no longer exist + if (p->timer.data) { + uv_close((uv_handle_t*)&p->timer, on_timer_close); + } + uv_close((uv_handle_t*)&p->handle, on_handle_close); +} + + +static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { + redisContext *c = &(ac->c); + + if (ac->ev.data != NULL) { + return REDIS_ERR; + } + + ac->ev.addRead = redisLibuvAddRead; + ac->ev.delRead = redisLibuvDelRead; + ac->ev.addWrite = redisLibuvAddWrite; + ac->ev.delWrite = redisLibuvDelWrite; + ac->ev.cleanup = redisLibuvCleanup; + ac->ev.scheduleTimer = redisLibuvSetTimeout; + + redisLibuvEvents* p = (redisLibuvEvents*)hi_malloc(sizeof(*p)); + if (p == NULL) + return REDIS_ERR; + + memset(p, 0, sizeof(*p)); + + if (uv_poll_init_socket(loop, &p->handle, c->fd) != 0) { + return REDIS_ERR; + } + + ac->ev.data = p; + p->handle.data = p; + p->context = ac; + + return REDIS_OK; +} +#endif diff --git a/deps/hiredis/adapters/macosx.h b/deps/hiredis/adapters/macosx.h new file mode 100644 index 0000000..3c87f1b --- /dev/null +++ b/deps/hiredis/adapters/macosx.h @@ -0,0 +1,115 @@ +// +// Created by Дмитрий Бахвалов on 13.07.15. +// Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. +// + +#ifndef __HIREDIS_MACOSX_H__ +#define __HIREDIS_MACOSX_H__ + +#include <CoreFoundation/CoreFoundation.h> + +#include "../hiredis.h" +#include "../async.h" + +typedef struct { + redisAsyncContext *context; + CFSocketRef socketRef; + CFRunLoopSourceRef sourceRef; +} RedisRunLoop; + +static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { + if( redisRunLoop != NULL ) { + if( redisRunLoop->sourceRef != NULL ) { + CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); + CFRelease(redisRunLoop->sourceRef); + } + if( redisRunLoop->socketRef != NULL ) { + CFSocketInvalidate(redisRunLoop->socketRef); + CFRelease(redisRunLoop->socketRef); + } + hi_free(redisRunLoop); + } + return REDIS_ERR; +} + +static void redisMacOSAddRead(void *privdata) { + RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; + CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); +} + +static void redisMacOSDelRead(void *privdata) { + RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; + CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); +} + +static void redisMacOSAddWrite(void *privdata) { + RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; + CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); +} + +static void redisMacOSDelWrite(void *privdata) { + RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; + CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); +} + +static void redisMacOSCleanup(void *privdata) { + RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; + freeRedisRunLoop(redisRunLoop); +} + +static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { + redisAsyncContext* context = (redisAsyncContext*) info; + + switch (callbackType) { + case kCFSocketReadCallBack: + redisAsyncHandleRead(context); + break; + + case kCFSocketWriteCallBack: + redisAsyncHandleWrite(context); + break; + + default: + break; + } +} + +static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { + redisContext *redisCtx = &(redisAsyncCtx->c); + + /* Nothing should be attached when something is already attached */ + if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; + + RedisRunLoop* redisRunLoop = (RedisRunLoop*) hi_calloc(1, sizeof(RedisRunLoop)); + if (redisRunLoop == NULL) + return REDIS_ERR; + + /* Setup redis stuff */ + redisRunLoop->context = redisAsyncCtx; + + redisAsyncCtx->ev.addRead = redisMacOSAddRead; + redisAsyncCtx->ev.delRead = redisMacOSDelRead; + redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; + redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; + redisAsyncCtx->ev.cleanup = redisMacOSCleanup; + redisAsyncCtx->ev.data = redisRunLoop; + + /* Initialize and install read/write events */ + CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; + + redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, + kCFSocketReadCallBack | kCFSocketWriteCallBack, + redisMacOSAsyncCallback, + &socketCtx); + if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); + + redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); + if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); + + CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); + + return REDIS_OK; +} + +#endif + diff --git a/deps/hiredis/adapters/poll.h b/deps/hiredis/adapters/poll.h new file mode 100644 index 0000000..f138650 --- /dev/null +++ b/deps/hiredis/adapters/poll.h @@ -0,0 +1,197 @@ + +#ifndef HIREDIS_POLL_H +#define HIREDIS_POLL_H + +#include "../async.h" +#include "../sockcompat.h" +#include <string.h> // for memset +#include <errno.h> + +/* Values to return from redisPollTick */ +#define REDIS_POLL_HANDLED_READ 1 +#define REDIS_POLL_HANDLED_WRITE 2 +#define REDIS_POLL_HANDLED_TIMEOUT 4 + +/* An adapter to allow manual polling of the async context by checking the state + * of the underlying file descriptor. Useful in cases where there is no formal + * IO event loop but regular ticking can be used, such as in game engines. */ + +typedef struct redisPollEvents { + redisAsyncContext *context; + redisFD fd; + char reading, writing; + char in_tick; + char deleted; + double deadline; +} redisPollEvents; + +static double redisPollTimevalToDouble(struct timeval *tv) { + if (tv == NULL) + return 0.0; + return tv->tv_sec + tv->tv_usec / 1000000.00; +} + +static double redisPollGetNow(void) { +#ifndef _MSC_VER + struct timeval tv; + gettimeofday(&tv,NULL); + return redisPollTimevalToDouble(&tv); +#else + FILETIME ft; + ULARGE_INTEGER li; + GetSystemTimeAsFileTime(&ft); + li.HighPart = ft.dwHighDateTime; + li.LowPart = ft.dwLowDateTime; + return (double)li.QuadPart * 1e-7; +#endif +} + +/* Poll for io, handling any pending callbacks. The timeout argument can be + * positive to wait for a maximum given time for IO, zero to poll, or negative + * to wait forever */ +static int redisPollTick(redisAsyncContext *ac, double timeout) { + int reading, writing; + struct pollfd pfd; + int handled; + int ns; + int itimeout; + + redisPollEvents *e = (redisPollEvents*)ac->ev.data; + if (!e) + return 0; + + /* local flags, won't get changed during callbacks */ + reading = e->reading; + writing = e->writing; + if (!reading && !writing) + return 0; + + pfd.fd = e->fd; + pfd.events = 0; + if (reading) + pfd.events = POLLIN; + if (writing) + pfd.events |= POLLOUT; + + if (timeout >= 0.0) { + itimeout = (int)(timeout * 1000.0); + } else { + itimeout = -1; + } + + ns = poll(&pfd, 1, itimeout); + if (ns < 0) { + /* ignore the EINTR error */ + if (errno != EINTR) + return ns; + ns = 0; + } + + handled = 0; + e->in_tick = 1; + if (ns) { + if (reading && (pfd.revents & POLLIN)) { + redisAsyncHandleRead(ac); + handled |= REDIS_POLL_HANDLED_READ; + } + /* on Windows, connection failure is indicated with the Exception fdset. + * handle it the same as writable. */ + if (writing && (pfd.revents & (POLLOUT | POLLERR))) { + /* context Read callback may have caused context to be deleted, e.g. + by doing an redisAsyncDisconnect() */ + if (!e->deleted) { + redisAsyncHandleWrite(ac); + handled |= REDIS_POLL_HANDLED_WRITE; + } + } + } + + /* perform timeouts */ + if (!e->deleted && e->deadline != 0.0) { + double now = redisPollGetNow(); + if (now >= e->deadline) { + /* deadline has passed. disable timeout and perform callback */ + e->deadline = 0.0; + redisAsyncHandleTimeout(ac); + handled |= REDIS_POLL_HANDLED_TIMEOUT; + } + } + + /* do a delayed cleanup if required */ + if (e->deleted) + hi_free(e); + else + e->in_tick = 0; + + return handled; +} + +static void redisPollAddRead(void *data) { + redisPollEvents *e = (redisPollEvents*)data; + e->reading = 1; +} + +static void redisPollDelRead(void *data) { + redisPollEvents *e = (redisPollEvents*)data; + e->reading = 0; +} + +static void redisPollAddWrite(void *data) { + redisPollEvents *e = (redisPollEvents*)data; + e->writing = 1; +} + +static void redisPollDelWrite(void *data) { + redisPollEvents *e = (redisPollEvents*)data; + e->writing = 0; +} + +static void redisPollCleanup(void *data) { + redisPollEvents *e = (redisPollEvents*)data; + + /* if we are currently processing a tick, postpone deletion */ + if (e->in_tick) + e->deleted = 1; + else + hi_free(e); +} + +static void redisPollScheduleTimer(void *data, struct timeval tv) +{ + redisPollEvents *e = (redisPollEvents*)data; + double now = redisPollGetNow(); + e->deadline = now + redisPollTimevalToDouble(&tv); +} + +static int redisPollAttach(redisAsyncContext *ac) { + redisContext *c = &(ac->c); + redisPollEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisPollEvents*)hi_malloc(sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + memset(e, 0, sizeof(*e)); + + e->context = ac; + e->fd = c->fd; + e->reading = e->writing = 0; + e->in_tick = e->deleted = 0; + e->deadline = 0.0; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisPollAddRead; + ac->ev.delRead = redisPollDelRead; + ac->ev.addWrite = redisPollAddWrite; + ac->ev.delWrite = redisPollDelWrite; + ac->ev.scheduleTimer = redisPollScheduleTimer; + ac->ev.cleanup = redisPollCleanup; + ac->ev.data = e; + + return REDIS_OK; +} +#endif /* HIREDIS_POLL_H */ diff --git a/deps/hiredis/adapters/qt.h b/deps/hiredis/adapters/qt.h new file mode 100644 index 0000000..5cc02e6 --- /dev/null +++ b/deps/hiredis/adapters/qt.h @@ -0,0 +1,135 @@ +/*- + * Copyright (C) 2014 Pietro Cerutti <gahr@gahr.ch> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __HIREDIS_QT_H__ +#define __HIREDIS_QT_H__ +#include <QSocketNotifier> +#include "../async.h" + +static void RedisQtAddRead(void *); +static void RedisQtDelRead(void *); +static void RedisQtAddWrite(void *); +static void RedisQtDelWrite(void *); +static void RedisQtCleanup(void *); + +class RedisQtAdapter : public QObject { + + Q_OBJECT + + friend + void RedisQtAddRead(void * adapter) { + RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter); + a->addRead(); + } + + friend + void RedisQtDelRead(void * adapter) { + RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter); + a->delRead(); + } + + friend + void RedisQtAddWrite(void * adapter) { + RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter); + a->addWrite(); + } + + friend + void RedisQtDelWrite(void * adapter) { + RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter); + a->delWrite(); + } + + friend + void RedisQtCleanup(void * adapter) { + RedisQtAdapter * a = static_cast<RedisQtAdapter *>(adapter); + a->cleanup(); + } + + public: + RedisQtAdapter(QObject * parent = 0) + : QObject(parent), m_ctx(0), m_read(0), m_write(0) { } + + ~RedisQtAdapter() { + if (m_ctx != 0) { + m_ctx->ev.data = NULL; + } + } + + int setContext(redisAsyncContext * ac) { + if (ac->ev.data != NULL) { + return REDIS_ERR; + } + m_ctx = ac; + m_ctx->ev.data = this; + m_ctx->ev.addRead = RedisQtAddRead; + m_ctx->ev.delRead = RedisQtDelRead; + m_ctx->ev.addWrite = RedisQtAddWrite; + m_ctx->ev.delWrite = RedisQtDelWrite; + m_ctx->ev.cleanup = RedisQtCleanup; + return REDIS_OK; + } + + private: + void addRead() { + if (m_read) return; + m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0); + connect(m_read, SIGNAL(activated(int)), this, SLOT(read())); + } + + void delRead() { + if (!m_read) return; + delete m_read; + m_read = 0; + } + + void addWrite() { + if (m_write) return; + m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0); + connect(m_write, SIGNAL(activated(int)), this, SLOT(write())); + } + + void delWrite() { + if (!m_write) return; + delete m_write; + m_write = 0; + } + + void cleanup() { + delRead(); + delWrite(); + } + + private slots: + void read() { redisAsyncHandleRead(m_ctx); } + void write() { redisAsyncHandleWrite(m_ctx); } + + private: + redisAsyncContext * m_ctx; + QSocketNotifier * m_read; + QSocketNotifier * m_write; +}; + +#endif /* !__HIREDIS_QT_H__ */ diff --git a/deps/hiredis/adapters/redismoduleapi.h b/deps/hiredis/adapters/redismoduleapi.h new file mode 100644 index 0000000..8a076fe --- /dev/null +++ b/deps/hiredis/adapters/redismoduleapi.h @@ -0,0 +1,144 @@ +#ifndef __HIREDIS_REDISMODULEAPI_H__ +#define __HIREDIS_REDISMODULEAPI_H__ + +#include "redismodule.h" + +#include "../async.h" +#include "../hiredis.h" + +#include <sys/types.h> + +typedef struct redisModuleEvents { + redisAsyncContext *context; + RedisModuleCtx *module_ctx; + int fd; + int reading, writing; + int timer_active; + RedisModuleTimerID timer_id; +} redisModuleEvents; + +static inline void redisModuleReadEvent(int fd, void *privdata, int mask) { + (void) fd; + (void) mask; + + redisModuleEvents *e = (redisModuleEvents*)privdata; + redisAsyncHandleRead(e->context); +} + +static inline void redisModuleWriteEvent(int fd, void *privdata, int mask) { + (void) fd; + (void) mask; + + redisModuleEvents *e = (redisModuleEvents*)privdata; + redisAsyncHandleWrite(e->context); +} + +static inline void redisModuleAddRead(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (!e->reading) { + e->reading = 1; + RedisModule_EventLoopAdd(e->fd, REDISMODULE_EVENTLOOP_READABLE, redisModuleReadEvent, e); + } +} + +static inline void redisModuleDelRead(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (e->reading) { + e->reading = 0; + RedisModule_EventLoopDel(e->fd, REDISMODULE_EVENTLOOP_READABLE); + } +} + +static inline void redisModuleAddWrite(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (!e->writing) { + e->writing = 1; + RedisModule_EventLoopAdd(e->fd, REDISMODULE_EVENTLOOP_WRITABLE, redisModuleWriteEvent, e); + } +} + +static inline void redisModuleDelWrite(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (e->writing) { + e->writing = 0; + RedisModule_EventLoopDel(e->fd, REDISMODULE_EVENTLOOP_WRITABLE); + } +} + +static inline void redisModuleStopTimer(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + if (e->timer_active) { + RedisModule_StopTimer(e->module_ctx, e->timer_id, NULL); + } + e->timer_active = 0; +} + +static inline void redisModuleCleanup(void *privdata) { + redisModuleEvents *e = (redisModuleEvents*)privdata; + redisModuleDelRead(privdata); + redisModuleDelWrite(privdata); + redisModuleStopTimer(privdata); + hi_free(e); +} + +static inline void redisModuleTimeout(RedisModuleCtx *ctx, void *privdata) { + (void) ctx; + + redisModuleEvents *e = (redisModuleEvents*)privdata; + e->timer_active = 0; + redisAsyncHandleTimeout(e->context); +} + +static inline void redisModuleSetTimeout(void *privdata, struct timeval tv) { + redisModuleEvents* e = (redisModuleEvents*)privdata; + + redisModuleStopTimer(privdata); + + mstime_t millis = tv.tv_sec * 1000 + tv.tv_usec / 1000.0; + e->timer_id = RedisModule_CreateTimer(e->module_ctx, millis, redisModuleTimeout, e); + e->timer_active = 1; +} + +/* Check if Redis version is compatible with the adapter. */ +static inline int redisModuleCompatibilityCheck(void) { + if (!RedisModule_EventLoopAdd || + !RedisModule_EventLoopDel || + !RedisModule_CreateTimer || + !RedisModule_StopTimer) { + return REDIS_ERR; + } + return REDIS_OK; +} + +static inline int redisModuleAttach(redisAsyncContext *ac, RedisModuleCtx *module_ctx) { + redisContext *c = &(ac->c); + redisModuleEvents *e; + + /* Nothing should be attached when something is already attached */ + if (ac->ev.data != NULL) + return REDIS_ERR; + + /* Create container for context and r/w events */ + e = (redisModuleEvents*)hi_malloc(sizeof(*e)); + if (e == NULL) + return REDIS_ERR; + + e->context = ac; + e->module_ctx = module_ctx; + e->fd = c->fd; + e->reading = e->writing = 0; + e->timer_active = 0; + + /* Register functions to start/stop listening for events */ + ac->ev.addRead = redisModuleAddRead; + ac->ev.delRead = redisModuleDelRead; + ac->ev.addWrite = redisModuleAddWrite; + ac->ev.delWrite = redisModuleDelWrite; + ac->ev.cleanup = redisModuleCleanup; + ac->ev.scheduleTimer = redisModuleSetTimeout; + ac->ev.data = e; + + return REDIS_OK; +} + +#endif |