| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #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); |
| 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__ */ |