1 #ifndef __HIREDIS_GLIB_H__
2 #define __HIREDIS_GLIB_H__
3
4 #include <glib.h>
5
6 #include "../hiredis.h"
7 #include "../async.h"
8
9 typedef struct
10 {
11 GSource source;
12 redisAsyncContext *ac;
13 GPollFD poll_fd;
14 } RedisSource;
15
16 static void
redis_source_add_read(gpointer data)17 redis_source_add_read (gpointer data)
18 {
19 RedisSource *source = (RedisSource *)data;
20 g_return_if_fail(source);
21 source->poll_fd.events |= G_IO_IN;
22 g_main_context_wakeup(g_source_get_context((GSource *)data));
23 }
24
25 static void
redis_source_del_read(gpointer data)26 redis_source_del_read (gpointer data)
27 {
28 RedisSource *source = (RedisSource *)data;
29 g_return_if_fail(source);
30 source->poll_fd.events &= ~G_IO_IN;
31 g_main_context_wakeup(g_source_get_context((GSource *)data));
32 }
33
34 static void
redis_source_add_write(gpointer data)35 redis_source_add_write (gpointer data)
36 {
37 RedisSource *source = (RedisSource *)data;
38 g_return_if_fail(source);
39 source->poll_fd.events |= G_IO_OUT;
40 g_main_context_wakeup(g_source_get_context((GSource *)data));
41 }
42
43 static void
redis_source_del_write(gpointer data)44 redis_source_del_write (gpointer data)
45 {
46 RedisSource *source = (RedisSource *)data;
47 g_return_if_fail(source);
48 source->poll_fd.events &= ~G_IO_OUT;
49 g_main_context_wakeup(g_source_get_context((GSource *)data));
50 }
51
52 static void
redis_source_cleanup(gpointer data)53 redis_source_cleanup (gpointer data)
54 {
55 RedisSource *source = (RedisSource *)data;
56
57 g_return_if_fail(source);
58
59 redis_source_del_read(source);
60 redis_source_del_write(source);
61 /*
62 * It is not our responsibility to remove ourself from the
63 * current main loop. However, we will remove the GPollFD.
64 */
65 if (source->poll_fd.fd >= 0) {
66 g_source_remove_poll((GSource *)data, &source->poll_fd);
67 source->poll_fd.fd = -1;
68 }
69 }
70
71 static gboolean
redis_source_prepare(GSource * source,gint * timeout_)72 redis_source_prepare (GSource *source,
73 gint *timeout_)
74 {
75 RedisSource *redis = (RedisSource *)source;
76 *timeout_ = -1;
77 return !!(redis->poll_fd.events & redis->poll_fd.revents);
78 }
79
80 static gboolean
redis_source_check(GSource * source)81 redis_source_check (GSource *source)
82 {
83 RedisSource *redis = (RedisSource *)source;
84 return !!(redis->poll_fd.events & redis->poll_fd.revents);
85 }
86
87 static gboolean
redis_source_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)88 redis_source_dispatch (GSource *source,
89 GSourceFunc callback,
90 gpointer user_data)
91 {
92 RedisSource *redis = (RedisSource *)source;
93
94 if ((redis->poll_fd.revents & G_IO_OUT)) {
95 redisAsyncHandleWrite(redis->ac);
96 redis->poll_fd.revents &= ~G_IO_OUT;
97 }
98
99 if ((redis->poll_fd.revents & G_IO_IN)) {
100 redisAsyncHandleRead(redis->ac);
101 redis->poll_fd.revents &= ~G_IO_IN;
102 }
103
104 if (callback) {
105 return callback(user_data);
106 }
107
108 return TRUE;
109 }
110
111 static void
redis_source_finalize(GSource * source)112 redis_source_finalize (GSource *source)
113 {
114 RedisSource *redis = (RedisSource *)source;
115
116 if (redis->poll_fd.fd >= 0) {
117 g_source_remove_poll(source, &redis->poll_fd);
118 redis->poll_fd.fd = -1;
119 }
120 }
121
122 static GSource *
redis_source_new(redisAsyncContext * ac)123 redis_source_new (redisAsyncContext *ac)
124 {
125 static GSourceFuncs source_funcs = {
126 .prepare = redis_source_prepare,
127 .check = redis_source_check,
128 .dispatch = redis_source_dispatch,
129 .finalize = redis_source_finalize,
130 };
131 redisContext *c = &ac->c;
132 RedisSource *source;
133
134 g_return_val_if_fail(ac != NULL, NULL);
135
136 source = (RedisSource *)g_source_new(&source_funcs, sizeof *source);
137 if (source == NULL)
138 return NULL;
139
140 source->ac = ac;
141 source->poll_fd.fd = c->fd;
142 source->poll_fd.events = 0;
143 source->poll_fd.revents = 0;
144 g_source_add_poll((GSource *)source, &source->poll_fd);
145
146 ac->ev.addRead = redis_source_add_read;
147 ac->ev.delRead = redis_source_del_read;
148 ac->ev.addWrite = redis_source_add_write;
149 ac->ev.delWrite = redis_source_del_write;
150 ac->ev.cleanup = redis_source_cleanup;
151 ac->ev.data = source;
152
153 return (GSource *)source;
154 }
155
156 #endif /* __HIREDIS_GLIB_H__ */
157