Allow to set event loop type with api
[platform/core/api/vine.git] / src / vine-event-loop-epoll.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17
18 #include <sys/eventfd.h>
19 #include <unistd.h>
20 #include <stdint.h>
21
22 #include "vine.h"
23 #include "vine-event-loop.h"
24 #include "vine-queue.h"
25 #include "vine-log.h"
26 #include "vine-utils.h"
27
28 static pthread_t __vine_event_loop_epoll_tid = 0;
29
30 static bool __cleanup = false;
31 static int __vine_epoll_fd = 0;
32 //static struct epoll_event __vine_epoll_events[MAX_VINE_EPOLL_EVENTS];
33 //static int __vine_epoll_events_idx = 0;
34
35 typedef struct {
36         int fd;
37         vine_poll_handler handler;
38         void *user_data;
39 } vine_epoll_io_event_handler;
40
41 typedef struct {
42         void *event_data;
43         vine_event_handler handler;
44         vine_event_free_handler free_func;
45         void *user_data;
46 } vine_epoll_event;
47
48 typedef struct {
49         int fd;
50         VineQueue<vine_epoll_event *> event_queue;
51 } vine_epoll_event_queue_s;
52
53 #ifdef FD_SETSIZE
54 #define MAX_IO_EVENT_HANDLERS FD_SETSIZE
55 #else
56 #define MAX_IO_EVENT_HANDLERS MAX_VINE_FDS
57 #endif
58
59 static vine_epoll_io_event_handler *io_event_handlers[MAX_IO_EVENT_HANDLERS] = {0, };
60
61 static void *__vine_event_loop_epoll_run(void *arg)
62 {
63         VINE_LOGD("Run Vine event loop");
64
65         struct epoll_event events[MAX_VINE_FDS];
66         int timeout = -1;
67
68         do {
69                 int n = epoll_wait(__vine_epoll_fd, events,     MAX_VINE_FDS, timeout);
70                 if (n == -1) {
71                         VINE_LOGE("Invalid return value");
72                         break;
73                 }
74
75                 for (int i = 0; i < n; ++i) {
76                         vine_epoll_io_event_handler *h = (vine_epoll_io_event_handler *)events[i].data.ptr;
77                         if (h && h->handler)
78                                 h->handler(h->fd, events[i].events, h->user_data);
79                 }
80         } while (!__cleanup);
81
82         // TODO:
83         // Even although __cleanup is set as false,
84         // this loop cannot be broken if waiting epoll_wait()
85         // --> socketpair()? timeout?
86
87         return NULL;
88 }
89
90 int vine_event_loop_epoll_init()
91 {
92         __vine_epoll_fd = epoll_create1(0);
93         if (__vine_epoll_fd == -1) {
94                 VINE_LOGE("Fail to create epoll fd. error %d", errno);
95                 return VINE_ERROR_OPERATION_FAILED;
96         }
97
98         __cleanup = false;
99
100         return VINE_ERROR_NONE;
101 }
102
103 void vine_event_loop_epoll_deinit()
104 {
105         close(__vine_epoll_fd);
106 }
107
108 int vine_event_loop_epoll_start()
109 {
110         VINE_LOGD("vine_event_loop_start");
111         if (__vine_event_loop_epoll_tid) {
112                 VINE_LOGD("Vine event loop was already executed");
113                 return VINE_ERROR_NONE;
114         }
115
116         if (pthread_create(&__vine_event_loop_epoll_tid, NULL,
117                         __vine_event_loop_epoll_run, NULL) != 0) {
118                 VINE_LOGE("Fail to create event thread");
119                 return VINE_ERROR_OPERATION_FAILED;
120         }
121
122         // pthread_detach(__vine_event_loop_tid);
123
124         return VINE_ERROR_NONE;
125 }
126
127 static void _vine_event_loop_epoll_wake_up()
128 {
129         uint64_t v = 1;
130         int fd = eventfd(0, 0);
131
132         VINE_LOGD("fd[%d] to wake the eventloop up", fd);
133         vine_event_loop_add_io_handler(fd, VINE_POLLOUT, NULL, NULL);
134         if (write(fd, &v, sizeof(v)) == -1)
135                 VINE_LOGE("Write error(%d)", errno);
136 }
137
138 void vine_event_loop_epoll_stop()
139 {
140         VINE_LOGD("vine_event_loop_stop");
141         __cleanup = true;
142         _vine_event_loop_epoll_wake_up();
143         pthread_join(__vine_event_loop_epoll_tid, NULL);
144         __vine_event_loop_epoll_tid = 0;
145 }
146
147 int vine_event_queue_epoll_create(vine_event_queue_h *event_queue)
148 {
149         vine_epoll_event_queue_s *event_queue_handle = new vine_epoll_event_queue_s;
150         VINE_LOGD("New Event Loop handle[%p]", event_queue_handle);
151
152         *event_queue = event_queue_handle;
153         event_queue_handle->fd = eventfd(0, 0);
154         if (event_queue_handle->fd == -1) {
155                 VINE_LOGE("Fail to create eventfd. error %d", errno);
156                 delete event_queue_handle;
157                 return VINE_ERROR_OPERATION_FAILED;
158         }
159         VINE_LOGD("Event FD: %d", event_queue_handle->fd);
160
161         return VINE_ERROR_NONE;
162 }
163
164 void vine_event_queue_epoll_destroy(vine_event_queue_h event_queue)
165 {
166         vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue;
167
168         vine_epoll_event *event = NULL;
169         while(!event_queue_handle->event_queue.empty()) {
170                 event = event_queue_handle->event_queue.front();
171                 if (event && event->free_func)
172                         event->free_func(event->event_data);
173                 event_queue_handle->event_queue.pop();
174                 free(event);
175         }
176
177         if (event_queue_handle->fd >= 0)
178                 close(event_queue_handle->fd);
179         delete event_queue_handle;
180 }
181
182 void vine_event_loop_epoll_get_eventfd(vine_event_queue_h event_queue, int *eventfd)
183 {
184         vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue;
185         *eventfd = event_queue_handle->fd;
186 }
187
188 static void _add_io_event_handler(int fd, vine_epoll_io_event_handler *h)
189 {
190         if (io_event_handlers[fd])
191                 free(io_event_handlers[fd]);
192         io_event_handlers[fd] = h;
193 }
194
195 static void _del_io_event_handler(int fd)
196 {
197         if (io_event_handlers[fd]) {
198                 free(io_event_handlers[fd]);
199                 io_event_handlers[fd] = NULL;
200         }
201 }
202
203 static vine_epoll_io_event_handler *_find_io_event_handler(int fd)
204 {
205         return io_event_handlers[fd];
206 }
207
208 int vine_event_loop_epoll_add_io_handler(
209         int fd, int events, vine_poll_handler handler, void *user_data)
210 {
211         RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
212                 "fd should be equal to or greater than zero");
213
214         vine_epoll_io_event_handler *h =
215                 (vine_epoll_io_event_handler *)calloc(1, sizeof(vine_epoll_io_event_handler));
216         RET_VAL_IF(h == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of memory");
217         h->fd = fd;
218         h->handler = handler;
219         h->user_data = user_data;
220         _add_io_event_handler(fd, h);
221
222         struct epoll_event event;
223         event.events = events;
224         event.data.ptr = (void *)h;
225
226         epoll_ctl(__vine_epoll_fd, EPOLL_CTL_ADD, fd, &event);
227         VINE_LOGD("Add an epoll event. fd: %d", fd);
228
229         return VINE_ERROR_NONE;
230 }
231
232 int vine_event_loop_epoll_mod_io_handler(
233         int fd, int events, vine_poll_handler handler, void *user_data)
234 {
235         RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
236                 "fd should be equal to or greater than zero");
237
238         struct epoll_event event;
239         event.events = events;
240         event.data.ptr = _find_io_event_handler(fd);
241
242         epoll_ctl(__vine_epoll_fd, EPOLL_CTL_MOD, fd, &event);
243         VINE_LOGD("Modify an epoll event. fd: %d event: %d", fd, events);
244
245         return VINE_ERROR_NONE;
246 }
247
248 int vine_event_loop_epoll_del_io_handler(int fd)
249 {
250         RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
251                 "fd should be equal to or greater than zero");
252
253         epoll_ctl(__vine_epoll_fd, EPOLL_CTL_DEL, fd, NULL);
254         _del_io_event_handler(fd);
255         VINE_LOGD("Del an epoll event. fd: %d", fd);
256
257         return VINE_ERROR_NONE;
258 }
259
260 // Register an event handler which is called in vine_event_loop_process()
261 // And then, an appropriate user callback will be called by the handler.
262 int vine_event_loop_epoll_add_event(vine_event_queue_h event_queue, void *event_data,
263         vine_event_handler handler, vine_event_free_handler free_func,
264         void *user_data)
265 {
266         VINE_LOGD("event_data[%p] event_queue[%p]", event_data, event_queue);
267         vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue;
268         RET_VAL_IF(event_queue == NULL, VINE_ERROR_INVALID_OPERATION, "event_queue is NULL");
269
270         vine_epoll_event *event = (vine_epoll_event *)calloc(1, sizeof(vine_epoll_event));
271         RET_VAL_IF(event == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of memory");
272
273         event->event_data = event_data;
274         event->handler = handler;
275         event->free_func = free_func;
276         event->user_data = user_data;
277         VINE_LOGD("Vine event[%p]", event);
278
279         event_queue_handle->event_queue.push(event);
280
281         uint64_t u = 1;
282         if (write(event_queue_handle->fd, &u, sizeof(uint64_t)) == -1) {
283                 VINE_LOGE("Write error(%d)", errno);
284                 return VINE_ERROR_OPERATION_FAILED;
285         }
286
287         return VINE_ERROR_NONE;
288 }
289
290 int vine_event_loop_epoll_process(vine_event_queue_h event_queue)
291 {
292         VINE_LOGD("Process a vine event. event_queue[%p]", event_queue);
293         vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue;
294         RET_VAL_IF(event_queue == NULL, VINE_ERROR_INVALID_OPERATION, "event_queue is NULL");
295
296         uint64_t u;
297         if (read(event_queue_handle->fd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) {
298                 VINE_LOGE("Read error(%d)", errno);
299                 return VINE_ERROR_OPERATION_FAILED;
300         }
301
302         VINE_LOGD("eventfd counter: %lld", u);
303
304         while (u-- && !event_queue_handle->event_queue.empty()) {
305                 vine_epoll_event *event = event_queue_handle->event_queue.front();
306                 event_queue_handle->event_queue.pop();
307                 if (event == NULL) {
308                         VINE_LOGE("vine event queue is empty");
309                         continue;
310                 }
311
312                 VINE_LOGD("Vine event[%p]", event);
313                 if (event->handler == NULL) {
314                         VINE_LOGI("No event handler");
315                         continue;
316                 }
317
318                 event->handler(event->event_data, event->user_data);
319                 if (event->free_func) {
320                         event->free_func(event->event_data);
321                 }
322         }
323
324         return VINE_ERROR_NONE;
325 }
326
327 vine_event_loop_fn vine_event_loop_epoll = {
328         .init = vine_event_loop_epoll_init,
329         .deinit = vine_event_loop_epoll_deinit,
330         .start = vine_event_loop_epoll_start,
331         .stop = vine_event_loop_epoll_stop,
332         .event_queue_create = vine_event_queue_epoll_create,
333         .event_queue_destroy = vine_event_queue_epoll_destroy,
334         .get_eventfd = vine_event_loop_epoll_get_eventfd,
335         .process = vine_event_loop_epoll_process,
336         .add_io_handler = vine_event_loop_epoll_add_io_handler,
337         .mod_io_handler = vine_event_loop_epoll_mod_io_handler,
338         .del_io_handler = vine_event_loop_epoll_del_io_handler,
339         .add_event = vine_event_loop_epoll_add_event,
340 };