| // SPDX-License-Identifier: LGPL-2.1+ | |
| // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> | |
| #include <stdlib.h> | |
| #include <errno.h> | |
| #include <unistd.h> | |
| #include <signal.h> | |
| #include <sys/epoll.h> | |
| #include "mainloop.h" | |
| #include "log.h" | |
| static int epfd = -1; | |
| static sig_atomic_t exit_mainloop; | |
| struct mainloop_data { | |
| mainloop_callback_t cb; | |
| void *data; | |
| int fd; | |
| }; | |
| #define MAX_EVENTS 10 | |
| int mainloop(unsigned int timeout) | |
| { | |
| int i, nfds; | |
| struct epoll_event events[MAX_EVENTS]; | |
| struct mainloop_data *md; | |
| if (epfd < 0) | |
| return -1; | |
| for (;;) { | |
| nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout); | |
| if (exit_mainloop || !nfds) | |
| return 0; | |
| if (nfds < 0) { | |
| if (errno == EINTR) | |
| continue; | |
| return -1; | |
| } | |
| for (i = 0; i < nfds; i++) { | |
| md = events[i].data.ptr; | |
| if (md->cb(md->fd, md->data) > 0) | |
| return 0; | |
| } | |
| } | |
| } | |
| int mainloop_add(int fd, mainloop_callback_t cb, void *data) | |
| { | |
| struct epoll_event ev = { | |
| .events = EPOLLIN, | |
| }; | |
| struct mainloop_data *md; | |
| md = malloc(sizeof(*md)); | |
| if (!md) | |
| return -1; | |
| md->data = data; | |
| md->cb = cb; | |
| md->fd = fd; | |
| ev.data.ptr = md; | |
| if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { | |
| free(md); | |
| return -1; | |
| } | |
| return 0; | |
| } | |
| int mainloop_del(int fd) | |
| { | |
| if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0) | |
| return -1; | |
| return 0; | |
| } | |
| int mainloop_init(void) | |
| { | |
| epfd = epoll_create(2); | |
| if (epfd < 0) | |
| return -1; | |
| return 0; | |
| } | |
| void mainloop_exit(void) | |
| { | |
| exit_mainloop = 1; | |
| } | |
| void mainloop_fini(void) | |
| { | |
| close(epfd); | |
| } |