File Coverage

src/libev_adapter.h
Criterion Covered Total %
statement 0 109 0.0
branch 0 58 0.0
condition n/a
subroutine n/a
pod n/a
total 0 167 0.0


line stmt bran cond sub pod time code
1             /* modified version of hiredis's libev adapter */
2             #ifndef __HIREDIS_LIBEV_H__
3             #define __HIREDIS_LIBEV_H__
4             #include "EXTERN.h"
5             #include "perl.h"
6             #include "XSUB.h"
7             #include "ppport.h"
8              
9             #include "EVAPI.h"
10              
11             #include "hiredis.h"
12             #include "async.h"
13              
14             typedef struct redisLibevEvents {
15             redisAsyncContext *context;
16             struct ev_loop *loop;
17             int reading, writing, timing;
18             ev_io rev, wev;
19             ev_timer timer;
20             } redisLibevEvents;
21              
22 0           static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
23             #if EV_MULTIPLICITY
24             ((void)loop);
25             #endif
26             ((void)revents);
27              
28 0           redisLibevEvents *e = (redisLibevEvents*)watcher->data;
29 0 0         if (e == NULL || e->context == NULL) return;
    0          
30 0           redisAsyncHandleRead(e->context);
31             }
32              
33 0           static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
34             #if EV_MULTIPLICITY
35             ((void)loop);
36             #endif
37             ((void)revents);
38              
39 0           redisLibevEvents *e = (redisLibevEvents*)watcher->data;
40 0 0         if (e == NULL || e->context == NULL) return;
    0          
41 0           redisAsyncHandleWrite(e->context);
42             }
43              
44 0           static void redisLibevAddRead(void *privdata) {
45 0           redisLibevEvents *e = (redisLibevEvents*)privdata;
46             struct ev_loop *loop;
47 0 0         if (e == NULL) return;
48 0           loop = e->loop;
49 0 0         if (loop == NULL) return;
50 0 0         if (!e->reading) {
51 0           e->reading = 1;
52 0           ev_io_start(loop, &e->rev);
53             }
54             }
55              
56 0           static void redisLibevDelRead(void *privdata) {
57 0           redisLibevEvents *e = (redisLibevEvents*)privdata;
58             struct ev_loop *loop;
59 0 0         if (e == NULL) return;
60 0           loop = e->loop;
61 0 0         if (e->reading) {
62 0           e->reading = 0;
63 0 0         if (loop != NULL) ev_io_stop(loop, &e->rev);
64             }
65             }
66              
67 0           static void redisLibevAddWrite(void *privdata) {
68 0           redisLibevEvents *e = (redisLibevEvents*)privdata;
69             struct ev_loop *loop;
70 0 0         if (e == NULL) return;
71 0           loop = e->loop;
72 0 0         if (loop == NULL) return;
73 0 0         if (!e->writing) {
74 0           e->writing = 1;
75 0           ev_io_start(loop, &e->wev);
76             }
77             }
78              
79 0           static void redisLibevDelWrite(void *privdata) {
80 0           redisLibevEvents *e = (redisLibevEvents*)privdata;
81             struct ev_loop *loop;
82 0 0         if (e == NULL) return;
83 0           loop = e->loop;
84 0 0         if (e->writing) {
85 0           e->writing = 0;
86 0 0         if (loop != NULL) ev_io_stop(loop, &e->wev);
87             }
88             }
89              
90 0           static void redisLibevCleanup(void *privdata) {
91 0           redisLibevEvents *e = (redisLibevEvents*)privdata;
92             redisAsyncContext *ctx;
93             struct ev_loop *loop;
94 0 0         if (e == NULL) return;
95              
96             /* Clear ev.data first to prevent double-cleanup if hiredis calls
97             * cleanup multiple times (e.g., disconnect then free). */
98 0           ctx = e->context;
99 0 0         if (ctx != NULL) {
100 0           ctx->ev.data = NULL;
101             }
102              
103 0           loop = e->loop;
104 0           e->loop = NULL;
105 0           e->context = NULL;
106              
107 0           e->rev.data = NULL;
108 0           e->wev.data = NULL;
109 0           e->timer.data = NULL;
110              
111 0 0         if (loop != NULL) {
112 0           ev_io_stop(loop, &e->rev);
113 0           ev_io_stop(loop, &e->wev);
114 0           ev_timer_stop(loop, &e->timer);
115             }
116              
117 0           Safefree(e);
118             }
119              
120 0           static void redisLibevTimeout(EV_P_ ev_timer *timer, int revents) {
121             #if EV_MULTIPLICITY
122             ((void)loop);
123             #endif
124             ((void)revents);
125              
126 0           redisLibevEvents *e = (redisLibevEvents*)timer->data;
127 0 0         if (e == NULL || e->context == NULL) return;
    0          
128 0           redisAsyncHandleTimeout(e->context);
129             }
130              
131 0           static void redisLibevSetTimeout(void *privdata, struct timeval tv) {
132 0           redisLibevEvents *e = (redisLibevEvents*)privdata;
133             struct ev_loop *loop;
134 0 0         if (e == NULL) return;
135 0           loop = e->loop;
136 0 0         if (loop == NULL) return;
137              
138 0           e->timing = 1;
139 0           e->timer.repeat = tv.tv_sec + tv.tv_usec / 1000000.00;
140 0           ev_timer_again(loop, &e->timer);
141             }
142              
143 0           static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
144 0           redisContext *c = &(ac->c);
145             redisLibevEvents *e;
146              
147             /* Nothing should be attached when something is already attached */
148 0 0         if (ac->ev.data != NULL)
149 0           return REDIS_ERR;
150              
151             /* Create container for context and r/w events */
152 0           Newx(e, 1, redisLibevEvents);
153 0           e->context = ac;
154             #if EV_MULTIPLICITY
155 0           e->loop = loop;
156             #else
157             #error "EV_MULTIPLICITY is required for EV::Redis libev adapter"
158             #endif
159 0           e->reading = e->writing = e->timing = 0;
160 0           e->rev.data = (void*)e;
161 0           e->wev.data = (void*)e;
162              
163             /* Register functions to start/stop listening for events */
164 0           ac->ev.addRead = redisLibevAddRead;
165 0           ac->ev.delRead = redisLibevDelRead;
166 0           ac->ev.addWrite = redisLibevAddWrite;
167 0           ac->ev.delWrite = redisLibevDelWrite;
168 0           ac->ev.cleanup = redisLibevCleanup;
169 0           ac->ev.scheduleTimer = redisLibevSetTimeout;
170 0           ac->ev.data = e;
171              
172             /* Initialize read/write events */
173 0           ev_io_init(&e->rev, redisLibevReadEvent, c->fd, EV_READ);
174 0           ev_io_init(&e->wev, redisLibevWriteEvent, c->fd, EV_WRITE);
175              
176             /* Initialize timer (but don't start it) so ev_set_priority is safe */
177 0           ev_init(&e->timer, redisLibevTimeout);
178 0           e->timer.data = (void*)e;
179              
180 0           return REDIS_OK;
181             }
182              
183 0           static void redisLibevSetPriority(redisAsyncContext *ac, int priority) {
184 0           redisLibevEvents *e = (redisLibevEvents*)ac->ev.data;
185             struct ev_loop *loop;
186 0 0         if (e == NULL) return;
187              
188 0           loop = e->loop;
189 0 0         if (loop == NULL) return;
190              
191             /* Stop watchers, set priority, restart if they were running */
192 0 0         if (e->reading) {
193 0           ev_io_stop(loop, &e->rev);
194 0           ev_set_priority(&e->rev, priority);
195 0           ev_io_start(loop, &e->rev);
196             } else {
197 0           ev_set_priority(&e->rev, priority);
198             }
199              
200 0 0         if (e->writing) {
201 0           ev_io_stop(loop, &e->wev);
202 0           ev_set_priority(&e->wev, priority);
203 0           ev_io_start(loop, &e->wev);
204             } else {
205 0           ev_set_priority(&e->wev, priority);
206             }
207              
208 0 0         if (e->timing) {
209 0           ev_timer_stop(loop, &e->timer);
210 0           ev_set_priority(&e->timer, priority);
211 0           ev_timer_again(loop, &e->timer);
212             } else {
213 0           ev_set_priority(&e->timer, priority);
214             }
215             }
216              
217             #endif