Simulation Core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

176 lines
5.5 KiB

  1. /*
  2. * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright notice,
  10. * this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * * Neither the name of Redis nor the names of its contributors may be used
  15. * to endorse or promote products derived from this software without
  16. * specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #ifndef __HIREDIS_LIBEVENT_H__
  31. #define __HIREDIS_LIBEVENT_H__
  32. #include <event2/event.h>
  33. #include "../hiredis.h"
  34. #include "../async.h"
  35. #define REDIS_LIBEVENT_DELETED 0x01
  36. #define REDIS_LIBEVENT_ENTERED 0x02
  37. typedef struct redisLibeventEvents {
  38. redisAsyncContext *context;
  39. struct event *ev;
  40. struct event_base *base;
  41. struct timeval tv;
  42. short flags;
  43. short state;
  44. } redisLibeventEvents;
  45. static void redisLibeventDestroy(redisLibeventEvents *e) {
  46. hi_free(e);
  47. }
  48. static void redisLibeventHandler(evutil_socket_t fd, short event, void *arg) {
  49. ((void)fd);
  50. redisLibeventEvents *e = (redisLibeventEvents*)arg;
  51. e->state |= REDIS_LIBEVENT_ENTERED;
  52. #define CHECK_DELETED() if (e->state & REDIS_LIBEVENT_DELETED) {\
  53. redisLibeventDestroy(e);\
  54. return; \
  55. }
  56. if ((event & EV_TIMEOUT) && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
  57. redisAsyncHandleTimeout(e->context);
  58. CHECK_DELETED();
  59. }
  60. if ((event & EV_READ) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
  61. redisAsyncHandleRead(e->context);
  62. CHECK_DELETED();
  63. }
  64. if ((event & EV_WRITE) && e->context && (e->state & REDIS_LIBEVENT_DELETED) == 0) {
  65. redisAsyncHandleWrite(e->context);
  66. CHECK_DELETED();
  67. }
  68. e->state &= ~REDIS_LIBEVENT_ENTERED;
  69. #undef CHECK_DELETED
  70. }
  71. static void redisLibeventUpdate(void *privdata, short flag, int isRemove) {
  72. redisLibeventEvents *e = (redisLibeventEvents *)privdata;
  73. const struct timeval *tv = e->tv.tv_sec || e->tv.tv_usec ? &e->tv : NULL;
  74. if (isRemove) {
  75. if ((e->flags & flag) == 0) {
  76. return;
  77. } else {
  78. e->flags &= ~flag;
  79. }
  80. } else {
  81. if (e->flags & flag) {
  82. return;
  83. } else {
  84. e->flags |= flag;
  85. }
  86. }
  87. event_del(e->ev);
  88. event_assign(e->ev, e->base, e->context->c.fd, e->flags | EV_PERSIST,
  89. redisLibeventHandler, privdata);
  90. event_add(e->ev, tv);
  91. }
  92. static void redisLibeventAddRead(void *privdata) {
  93. redisLibeventUpdate(privdata, EV_READ, 0);
  94. }
  95. static void redisLibeventDelRead(void *privdata) {
  96. redisLibeventUpdate(privdata, EV_READ, 1);
  97. }
  98. static void redisLibeventAddWrite(void *privdata) {
  99. redisLibeventUpdate(privdata, EV_WRITE, 0);
  100. }
  101. static void redisLibeventDelWrite(void *privdata) {
  102. redisLibeventUpdate(privdata, EV_WRITE, 1);
  103. }
  104. static void redisLibeventCleanup(void *privdata) {
  105. redisLibeventEvents *e = (redisLibeventEvents*)privdata;
  106. if (!e) {
  107. return;
  108. }
  109. event_del(e->ev);
  110. event_free(e->ev);
  111. e->ev = NULL;
  112. if (e->state & REDIS_LIBEVENT_ENTERED) {
  113. e->state |= REDIS_LIBEVENT_DELETED;
  114. } else {
  115. redisLibeventDestroy(e);
  116. }
  117. }
  118. static void redisLibeventSetTimeout(void *privdata, struct timeval tv) {
  119. redisLibeventEvents *e = (redisLibeventEvents *)privdata;
  120. short flags = e->flags;
  121. e->flags = 0;
  122. e->tv = tv;
  123. redisLibeventUpdate(e, flags, 0);
  124. }
  125. static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
  126. redisContext *c = &(ac->c);
  127. redisLibeventEvents *e;
  128. /* Nothing should be attached when something is already attached */
  129. if (ac->ev.data != NULL)
  130. return REDIS_ERR;
  131. /* Create container for context and r/w events */
  132. e = (redisLibeventEvents*)hi_calloc(1, sizeof(*e));
  133. if (e == NULL)
  134. return REDIS_ERR;
  135. e->context = ac;
  136. /* Register functions to start/stop listening for events */
  137. ac->ev.addRead = redisLibeventAddRead;
  138. ac->ev.delRead = redisLibeventDelRead;
  139. ac->ev.addWrite = redisLibeventAddWrite;
  140. ac->ev.delWrite = redisLibeventDelWrite;
  141. ac->ev.cleanup = redisLibeventCleanup;
  142. ac->ev.scheduleTimer = redisLibeventSetTimeout;
  143. ac->ev.data = e;
  144. /* Initialize and install read/write events */
  145. e->ev = event_new(base, c->fd, EV_READ | EV_WRITE, redisLibeventHandler, e);
  146. e->base = base;
  147. return REDIS_OK;
  148. }
  149. #endif