From de8eba84f26115e69832945f0be6c8e55637f9e6 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 20:13:14 +0900 Subject: [PATCH] sensord: ipc: add event_loop class - event_loop class is a wrapper of g_main_loop. - event_loop class has the role of I/O multiplexing. - event_handler interface can be added to event_loop. - it would be better to make event_loop interface to use the other main_loop.. but now, it is not necessary yet. - todo-list - add/remove idle handler Change-Id: I74dd0636d43319e64fa2701f9b3c662e3f31c575 Signed-off-by: kibak.yoon --- src/shared/event_handler.h | 36 ++++++ src/shared/event_loop.cpp | 268 +++++++++++++++++++++++++++++++++++++++++++++ src/shared/event_loop.h | 102 +++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 src/shared/event_handler.h create mode 100644 src/shared/event_loop.cpp create mode 100644 src/shared/event_loop.h diff --git a/src/shared/event_handler.h b/src/shared/event_handler.h new file mode 100644 index 0000000..26ab899 --- /dev/null +++ b/src/shared/event_handler.h @@ -0,0 +1,36 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed 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 __EVENT_HANDLER_H__ +#define __EVENT_HANDLER_H__ + +namespace ipc { + +typedef unsigned int event_condition; + +class event_handler { +public: + virtual ~event_handler() {} + + virtual bool handle(int fd, event_condition condition) = 0; +}; + +} + +#endif /* __EVENT_HANDLER_H__ */ diff --git a/src/shared/event_loop.cpp b/src/shared/event_loop.cpp new file mode 100644 index 0000000..9bd596a --- /dev/null +++ b/src/shared/event_loop.cpp @@ -0,0 +1,268 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed 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. + * + */ + +#include "event_loop.h" + +#include +#include +#include +#include +#include +#include + +#include "sensor_log.h" +#include "event_handler.h" + +#define BAD_HANDLE 0 + +using namespace ipc; + +static gboolean g_io_handler(GIOChannel *ch, GIOCondition condition, gpointer data) +{ + uint64_t id; + int fd; + bool term; + unsigned int cond; + + cond = (unsigned int)condition; + + if (cond & (G_IO_HUP)) + cond &= ~(G_IO_IN & G_IO_OUT); + + handler_info *info = (handler_info *)data; + id = info->id; + fd = info->fd; + term = info->loop->is_terminator(fd); + + if (cond & G_IO_NVAL) + return FALSE; + + bool ret = info->handler->handle(fd, (event_condition)cond); + + if (!ret && !term) { + info->loop->remove_event(id); + return FALSE; + } + + return TRUE; +} + +static gint on_timer(gpointer data) +{ + event_loop *loop = (event_loop *)data; + loop->stop(); + + return FALSE; +} + +event_loop::event_loop() +: m_mainloop(NULL) +, m_running(false) +, m_terminating(false) +, m_sequence(1) +, m_term_fd(-1) +{ + m_mainloop = g_main_loop_new(NULL, FALSE); +} + +event_loop::event_loop(GMainLoop *mainloop) +: m_mainloop(NULL) +, m_running(true) +, m_terminating(false) +, m_sequence(1) +, m_term_fd(-1) +{ + if (m_mainloop) { + g_main_loop_quit(m_mainloop); + g_main_loop_unref(m_mainloop); + } + + m_mainloop = mainloop; +} + +event_loop::~event_loop() +{ + remove_all_events(); +} + +uint64_t event_loop::add_event(const int fd, const event_condition cond, event_handler *handler) +{ + GIOChannel *ch = NULL; + GSource *src = NULL; + + retvm_if(m_terminating.load(), BAD_HANDLE, + "Failed to add event, because event_loop is being terminated"); + + ch = g_io_channel_unix_new(fd); + retvm_if(!ch, BAD_HANDLE, "Failed to create g_io_channel_unix_new"); + + src = g_io_create_watch(ch, (GIOCondition)(cond)); + if (!src) { + g_io_channel_unref(ch); + _E("Failed to create g_io_create_watch"); + return BAD_HANDLE; + } + + uint64_t id = m_sequence++; + + handler_info *info = new(std::nothrow) handler_info(id, fd, ch, src, handler, this); + retvm_if(!info, BAD_HANDLE, "Failed to allocate memory"); + + g_source_set_callback(src, (GSourceFunc) g_io_handler, info, NULL); + g_source_attach(src, g_main_loop_get_context(m_mainloop)); + + m_infos[id] = info; + + /* _D("Added[%llu](fd:%d)", id, fd); */ + return id; +} + +uint64_t event_loop::add_idle_event(unsigned int priority, idle_handler *handler) +{ + GSource *src; + + retvm_if(m_terminating.load(), false, + "Failed to remove event, because event_loop is terminated"); + + src = g_idle_source_new(); + retvm_if(!src, false, "Failed to allocate memory"); + + g_source_unref(src); + + /* Not Supported yet */ + return false; +} + +bool event_loop::remove_event(uint64_t id, bool close_channel) +{ + auto it = m_infos.find(id); + retv_if(it == m_infos.end(), false); + + if (close_channel) + g_io_channel_shutdown(it->second->g_ch, TRUE, NULL); + + release_info(it->second); + m_infos.erase(it); + + /* _D("Removed[%llu]", id); */ + return true; +} + +void event_loop::remove_all_events(void) +{ + auto it = m_infos.begin(); + while (it != m_infos.end()) { + release_info(it->second); + it = m_infos.erase(it); + } +} + +void event_loop::release_info(handler_info *info) +{ + ret_if(!info->g_ch || info->id == 0); + + g_source_destroy(info->g_src); + g_source_unref(info->g_src); + + g_io_channel_unref(info->g_ch); + info->g_ch = NULL; + + delete info->handler; + info->handler = NULL; + + delete info; +} + +class terminator : public event_handler +{ +public: + terminator(event_loop *loop) + : m_loop(loop) + { } + + bool handle(int fd, event_condition condition) + { + m_loop->terminate(); + return false; + } + +private: + event_loop *m_loop; +}; + +bool event_loop::run(int timeout) +{ + retvm_if(!m_mainloop, false, "Invalid GMainLoop"); + retv_if(is_running(), false); + + if (timeout > 0) { + GSource *src = g_timeout_source_new(timeout); + g_source_set_callback(src, on_timer, this, NULL); + g_source_attach(src, g_main_loop_get_context(m_mainloop)); + g_source_unref(src); + } + + m_term_fd = eventfd(0, 0); + retv_if(m_term_fd == -1, false); + + terminator *handler = new(std::nothrow) terminator(this); + retvm_if(!handler, false, "Failed to allocate memory"); + + add_event(m_term_fd, EVENT_IN | EVENT_HUP | EVENT_NVAL, handler); + + m_running.store(true); + + _I("Started"); + g_main_loop_run(m_mainloop); +} + +void event_loop::stop(void) +{ + ret_if(!is_running() || m_terminating.load()); + + uint64_t term = 1; + m_terminating.store(true); + write(m_term_fd, &term, sizeof(uint64_t)); +} + +void event_loop::terminate(void) +{ + remove_all_events(); + + if (m_mainloop) { + g_main_loop_quit(m_mainloop); + g_main_loop_unref(m_mainloop); + m_mainloop = NULL; + } + + m_running.store(false); + m_terminating.store(false); + + _I("Terminated"); +} + +bool event_loop::is_running(void) +{ + return m_running.load(); +} + +bool event_loop::is_terminator(int fd) +{ + return (m_term_fd == fd); +} diff --git a/src/shared/event_loop.h b/src/shared/event_loop.h new file mode 100644 index 0000000..934a8b4 --- /dev/null +++ b/src/shared/event_loop.h @@ -0,0 +1,102 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * Licensed 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 __EVENT_LOOP_H__ +#define __EVENT_LOOP_H__ + +#include +#include +#include +#include + +#include "event_handler.h" + +namespace ipc { + +enum event_condition_e { + EVENT_IN = G_IO_IN, + EVENT_OUT = G_IO_OUT, + EVENT_HUP = G_IO_HUP, + EVENT_NVAL = G_IO_NVAL, +}; + +/* move it to file */ +class idle_handler { + virtual ~idle_handler(); + bool handle(int fd); +}; + +class event_loop; + +class handler_info { +public: + handler_info(int64_t _id, int _fd, GIOChannel *_ch, GSource *_src, event_handler *_handler, event_loop *_loop) + : id(_id) + , fd(_fd) + , g_ch(_ch) + , g_src(_src) + , handler(_handler) + , loop(_loop) + {} + + uint64_t id; + int fd; + GIOChannel *g_ch; + GSource *g_src; + event_handler *handler; + event_loop *loop; +}; + +class event_loop { +public: + typedef unsigned int event_condition; + typedef bool (*idle_cb)(void *); + + event_loop(); + event_loop(GMainLoop *mainloop); + ~event_loop(); + + uint64_t add_event(const int fd, const event_condition cond, event_handler *handler); + uint64_t add_idle_event(unsigned int priority, idle_handler *handler); + + bool remove_event(uint64_t id, bool close_channel = false); + void remove_all_events(void); + + void release_info(handler_info *info); + + bool run(int timeout = 0); + void stop(void); + void terminate(void); + + bool is_running(void); + bool is_terminator(int fd); + +private: + GMainLoop *m_mainloop; + std::atomic m_running; + std::atomic m_terminating; + std::atomic m_sequence; + std::map m_infos; + + int m_term_fd; +}; + +} + +#endif /* __EVENT_LOOP_H__ */ -- 2.7.4