Fixed Heap corruption
[platform/core/system/sensord.git] / src / shared / event_loop.cpp
1 /*
2  * sensord
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include "event_loop.h"
21
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <unistd.h>
25 #include <time.h>
26 #include <sys/eventfd.h>
27 #include <glib.h>
28
29 #include "sensor_log.h"
30 #include "event_handler.h"
31
32 #define BAD_HANDLE 0
33
34 using namespace ipc;
35
36 static gboolean g_io_handler(GIOChannel *ch, GIOCondition condition, gpointer data)
37 {
38         uint64_t id;
39         int fd;
40         bool term;
41         unsigned int cond;
42
43         cond = (unsigned int)condition;
44
45         if (cond & (G_IO_HUP))
46                 cond &= ~(G_IO_IN | G_IO_OUT);
47
48         handler_info *info = (handler_info *)data;
49         id = info->id;
50         fd = info->fd;
51         term = info->loop->is_terminator(fd);
52
53         if (cond & G_IO_NVAL)
54                 return FALSE;
55
56         bool ret = info->handler->handle(fd, (event_condition)cond);
57
58         if (!ret && !term) {
59                 info->loop->remove_event(id);
60                 return FALSE;
61         }
62
63         return TRUE;
64 }
65
66 static gint on_timer(gpointer data)
67 {
68         event_loop *loop = (event_loop *)data;
69         loop->stop();
70
71         return FALSE;
72 }
73
74 event_loop::event_loop()
75 : m_mainloop(NULL)
76 , m_running(false)
77 , m_terminating(false)
78 , m_sequence(1)
79 , m_term_fd(-1)
80 {
81         m_mainloop = g_main_loop_new(NULL, FALSE);
82 }
83
84 event_loop::event_loop(GMainLoop *mainloop)
85 : m_mainloop(NULL)
86 , m_running(true)
87 , m_terminating(false)
88 , m_sequence(1)
89 , m_term_fd(-1)
90 {
91         if (m_mainloop) {
92                 g_main_loop_quit(m_mainloop);
93                 g_main_loop_unref(m_mainloop);
94         }
95
96         m_mainloop = mainloop;
97 }
98
99 event_loop::~event_loop()
100 {
101         remove_all_events();
102 }
103
104 uint64_t event_loop::add_event(const int fd, const event_condition cond, event_handler *handler)
105 {
106         GIOChannel *ch = NULL;
107         GSource *src = NULL;
108
109         retvm_if(m_terminating.load(), BAD_HANDLE,
110                         "Failed to add event, because event_loop is being terminated");
111
112         ch = g_io_channel_unix_new(fd);
113         retvm_if(!ch, BAD_HANDLE, "Failed to create g_io_channel_unix_new");
114
115         src = g_io_create_watch(ch, (GIOCondition)(cond));
116         if (!src) {
117                 g_io_channel_unref(ch);
118                 _E("Failed to create g_io_create_watch");
119                 return BAD_HANDLE;
120         }
121
122         uint64_t id = m_sequence++;
123
124         handler_info *info = new(std::nothrow) handler_info(id, fd, ch, src, handler, this);
125         retvm_if(!info, BAD_HANDLE, "Failed to allocate memory");
126
127         g_source_set_callback(src, (GSourceFunc) g_io_handler, info, NULL);
128         g_source_attach(src, g_main_loop_get_context(m_mainloop));
129
130         m_handlers[id] = info;
131
132         /* _D("Added[%llu](fd:%d)", id, fd); */
133         return id;
134 }
135
136 uint64_t event_loop::add_idle_event(unsigned int priority, idle_handler *handler)
137 {
138         GSource *src;
139
140         retvm_if(m_terminating.load(), false,
141                         "Failed to remove event, because event_loop is terminated");
142
143         src = g_idle_source_new();
144         retvm_if(!src, false, "Failed to allocate memory");
145
146         g_source_unref(src);
147
148         /* Not Supported yet */
149         return false;
150 }
151
152 bool event_loop::remove_event(uint64_t id, bool close_channel)
153 {
154         auto it = m_handlers.find(id);
155         retv_if(it == m_handlers.end(), false);
156
157         if (close_channel)
158                 g_io_channel_shutdown(it->second->g_ch, TRUE, NULL);
159
160         release_info(it->second);
161         m_handlers.erase(it);
162
163         /* _D("Removed[%llu]", id); */
164         return true;
165 }
166
167 void event_loop::remove_all_events(void)
168 {
169         auto it = m_handlers.begin();
170         while (it != m_handlers.end()) {
171                 release_info(it->second);
172                 it = m_handlers.erase(it);
173         }
174 }
175
176 void event_loop::release_info(handler_info *info)
177 {
178         ret_if(!info->g_ch || info->id == 0);
179
180         g_source_destroy(info->g_src);
181         g_source_unref(info->g_src);
182         info->g_src = NULL;
183
184         g_io_channel_unref(info->g_ch);
185         info->g_ch = NULL;
186
187         delete info->handler;
188         info->handler = NULL;
189
190         delete info;
191         info = NULL;
192 }
193
194 class terminator : public event_handler
195 {
196 public:
197         terminator(event_loop *loop)
198         : m_loop(loop)
199         { }
200
201         bool handle(int fd, event_condition condition)
202         {
203                 m_loop->terminate();
204                 return false;
205         }
206
207 private:
208         event_loop *m_loop;
209 };
210
211 bool event_loop::run(int timeout)
212 {
213         retvm_if(!m_mainloop, false, "Invalid GMainLoop");
214         retv_if(is_running(), false);
215
216         if (timeout > 0) {
217                 GSource *src = g_timeout_source_new(timeout);
218                 g_source_set_callback(src, on_timer, this, NULL);
219                 g_source_attach(src, g_main_loop_get_context(m_mainloop));
220                 g_source_unref(src);
221         }
222
223         m_term_fd = eventfd(0, 0);
224         retv_if(m_term_fd == -1, false);
225
226         terminator *handler = new(std::nothrow) terminator(this);
227         retvm_if(!handler, false, "Failed to allocate memory");
228
229         add_event(m_term_fd, EVENT_IN | EVENT_HUP | EVENT_NVAL, handler);
230
231         m_running.store(true);
232
233         _I("Started");
234         g_main_loop_run(m_mainloop);
235
236         return true;
237 }
238
239 void event_loop::stop(void)
240 {
241         ret_if(!is_running() || m_terminating.load());
242
243         terminate();
244 }
245
246 void event_loop::terminate(void)
247 {
248         remove_all_events();
249
250         if (m_mainloop) {
251                 g_main_loop_quit(m_mainloop);
252                 g_main_loop_unref(m_mainloop);
253                 m_mainloop = NULL;
254         }
255
256         m_running.store(false);
257         m_terminating.store(false);
258
259         _I("Terminated");
260 }
261
262 bool event_loop::is_running(void)
263 {
264         return m_running.load();
265 }
266
267 bool event_loop::is_terminator(int fd)
268 {
269         return (m_term_fd == fd);
270 }