| 1 | // SPDX-License-Identifier: LGPL-2.1+ |
| 2 | // Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> |
| 3 | #include <stdlib.h> |
| 4 | #include <errno.h> |
| 5 | #include <unistd.h> |
| 6 | #include <signal.h> |
| 7 | #include <sys/epoll.h> |
| 8 | #include "mainloop.h" |
| 9 | #include "log.h" |
| 10 | |
| 11 | static int epfd = -1; |
| 12 | static sig_atomic_t exit_mainloop; |
| 13 | |
| 14 | struct mainloop_data { |
| 15 | mainloop_callback_t cb; |
| 16 | void *data; |
| 17 | int fd; |
| 18 | }; |
| 19 | |
| 20 | #define MAX_EVENTS 10 |
| 21 | |
| 22 | int mainloop(unsigned int timeout) |
| 23 | { |
| 24 | int i, nfds; |
| 25 | struct epoll_event events[MAX_EVENTS]; |
| 26 | struct mainloop_data *md; |
| 27 | |
| 28 | if (epfd < 0) |
| 29 | return -1; |
| 30 | |
| 31 | for (;;) { |
| 32 | |
| 33 | nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout); |
| 34 | |
| 35 | if (exit_mainloop || !nfds) |
| 36 | return 0; |
| 37 | |
| 38 | if (nfds < 0) { |
| 39 | if (errno == EINTR) |
| 40 | continue; |
| 41 | return -1; |
| 42 | } |
| 43 | |
| 44 | for (i = 0; i < nfds; i++) { |
| 45 | md = events[i].data.ptr; |
| 46 | |
| 47 | if (md->cb(md->fd, md->data) > 0) |
| 48 | return 0; |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | int mainloop_add(int fd, mainloop_callback_t cb, void *data) |
| 54 | { |
| 55 | struct epoll_event ev = { |
| 56 | .events = EPOLLIN, |
| 57 | }; |
| 58 | |
| 59 | struct mainloop_data *md; |
| 60 | |
| 61 | md = malloc(sizeof(*md)); |
| 62 | if (!md) |
| 63 | return -1; |
| 64 | |
| 65 | md->data = data; |
| 66 | md->cb = cb; |
| 67 | md->fd = fd; |
| 68 | |
| 69 | ev.data.ptr = md; |
| 70 | |
| 71 | if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { |
| 72 | free(md); |
| 73 | return -1; |
| 74 | } |
| 75 | |
| 76 | return 0; |
| 77 | } |
| 78 | |
| 79 | int mainloop_del(int fd) |
| 80 | { |
| 81 | if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0) |
| 82 | return -1; |
| 83 | |
| 84 | return 0; |
| 85 | } |
| 86 | |
| 87 | int mainloop_init(void) |
| 88 | { |
| 89 | epfd = epoll_create(2); |
| 90 | if (epfd < 0) |
| 91 | return -1; |
| 92 | |
| 93 | return 0; |
| 94 | } |
| 95 | |
| 96 | void mainloop_exit(void) |
| 97 | { |
| 98 | exit_mainloop = 1; |
| 99 | } |
| 100 | |
| 101 | void mainloop_fini(void) |
| 102 | { |
| 103 | close(epfd); |
| 104 | } |
| 105 | |