2 * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/eventfd.h>
23 #include "vine-event-loop.h"
24 #include "vine-queue.h"
26 #include "vine-utils.h"
28 static pthread_t __vine_event_loop_epoll_tid = 0;
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;
37 vine_poll_handler handler;
39 } vine_epoll_io_event_handler;
43 vine_event_handler handler;
44 vine_event_free_handler free_func;
50 VineQueue<vine_epoll_event *> event_queue;
51 } vine_epoll_event_queue_s;
54 #define MAX_IO_EVENT_HANDLERS FD_SETSIZE
56 #define MAX_IO_EVENT_HANDLERS MAX_VINE_FDS
59 static vine_epoll_io_event_handler *io_event_handlers[MAX_IO_EVENT_HANDLERS] = {0, };
61 static void *__vine_event_loop_epoll_run(void *arg)
63 VINE_LOGD("Run Vine event loop");
65 struct epoll_event events[MAX_VINE_FDS];
69 int n = epoll_wait(__vine_epoll_fd, events, MAX_VINE_FDS, timeout);
71 VINE_LOGE("Invalid return value");
75 for (int i = 0; i < n; ++i) {
76 vine_epoll_io_event_handler *h = (vine_epoll_io_event_handler *)events[i].data.ptr;
78 h->handler(h->fd, events[i].events, h->user_data);
83 // Even although __cleanup is set as false,
84 // this loop cannot be broken if waiting epoll_wait()
85 // --> socketpair()? timeout?
90 int vine_event_loop_epoll_init()
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;
100 return VINE_ERROR_NONE;
103 void vine_event_loop_epoll_deinit()
105 close(__vine_epoll_fd);
108 int vine_event_loop_epoll_start()
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;
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;
122 // pthread_detach(__vine_event_loop_tid);
124 return VINE_ERROR_NONE;
127 static void _vine_event_loop_epoll_wake_up()
130 int fd = eventfd(0, 0);
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);
138 void vine_event_loop_epoll_stop()
140 VINE_LOGD("vine_event_loop_stop");
142 _vine_event_loop_epoll_wake_up();
143 pthread_join(__vine_event_loop_epoll_tid, NULL);
144 __vine_event_loop_epoll_tid = 0;
147 int vine_event_queue_epoll_create(vine_event_queue_h *event_queue)
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);
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;
159 VINE_LOGD("Event FD: %d", event_queue_handle->fd);
161 return VINE_ERROR_NONE;
164 void vine_event_queue_epoll_destroy(vine_event_queue_h event_queue)
166 vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue;
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();
177 if (event_queue_handle->fd >= 0)
178 close(event_queue_handle->fd);
179 delete event_queue_handle;
182 void vine_event_loop_epoll_get_eventfd(vine_event_queue_h event_queue, int *eventfd)
184 vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue;
185 *eventfd = event_queue_handle->fd;
188 static void _add_io_event_handler(int fd, vine_epoll_io_event_handler *h)
190 if (io_event_handlers[fd])
191 free(io_event_handlers[fd]);
192 io_event_handlers[fd] = h;
195 static void _del_io_event_handler(int fd)
197 if (io_event_handlers[fd]) {
198 free(io_event_handlers[fd]);
199 io_event_handlers[fd] = NULL;
203 static vine_epoll_io_event_handler *_find_io_event_handler(int fd)
205 return io_event_handlers[fd];
208 int vine_event_loop_epoll_add_io_handler(
209 int fd, int events, vine_poll_handler handler, void *user_data)
211 RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
212 "fd should be equal to or greater than zero");
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");
218 h->handler = handler;
219 h->user_data = user_data;
220 _add_io_event_handler(fd, h);
222 struct epoll_event event;
223 event.events = events;
224 event.data.ptr = (void *)h;
226 epoll_ctl(__vine_epoll_fd, EPOLL_CTL_ADD, fd, &event);
227 VINE_LOGD("Add an epoll event. fd: %d", fd);
229 return VINE_ERROR_NONE;
232 int vine_event_loop_epoll_mod_io_handler(
233 int fd, int events, vine_poll_handler handler, void *user_data)
235 RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
236 "fd should be equal to or greater than zero");
238 struct epoll_event event;
239 event.events = events;
240 event.data.ptr = _find_io_event_handler(fd);
242 epoll_ctl(__vine_epoll_fd, EPOLL_CTL_MOD, fd, &event);
243 VINE_LOGD("Modify an epoll event. fd: %d event: %d", fd, events);
245 return VINE_ERROR_NONE;
248 int vine_event_loop_epoll_del_io_handler(int fd)
250 RET_VAL_IF(fd < 0, VINE_ERROR_INVALID_PARAMETER,
251 "fd should be equal to or greater than zero");
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);
257 return VINE_ERROR_NONE;
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,
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");
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");
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);
279 event_queue_handle->event_queue.push(event);
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;
287 return VINE_ERROR_NONE;
290 int vine_event_loop_epoll_process(vine_event_queue_h event_queue)
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");
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;
302 VINE_LOGD("eventfd counter: %lld", u);
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();
308 VINE_LOGE("vine event queue is empty");
312 VINE_LOGD("Vine event[%p]", event);
313 if (event->handler == NULL) {
314 VINE_LOGI("No event handler");
318 event->handler(event->event_data, event->user_data);
319 if (event->free_func) {
320 event->free_func(event->event_data);
324 return VINE_ERROR_NONE;
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,