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 unsigned short nrhandler;
13 static sig_atomic_t exit_mainloop;
14
15 struct mainloop_data {
16 mainloop_callback_t cb;
17 void *data;
18 int fd;
19 };
20
21 static struct mainloop_data **mds;
22
23 #define MAX_EVENTS 10
24
mainloop(unsigned int timeout)25 int mainloop(unsigned int timeout)
26 {
27 int i, nfds;
28 struct epoll_event events[MAX_EVENTS];
29 struct mainloop_data *md;
30
31 if (epfd < 0)
32 return -1;
33
34 for (;;) {
35
36 nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout);
37
38 if (exit_mainloop || !nfds)
39 return 0;
40
41 if (nfds < 0) {
42 if (errno == EINTR)
43 continue;
44 return -1;
45 }
46
47 for (i = 0; i < nfds; i++) {
48 md = events[i].data.ptr;
49
50 if (md->cb(md->fd, md->data) > 0)
51 return 0;
52 }
53 }
54 }
55
mainloop_add(int fd,mainloop_callback_t cb,void * data)56 int mainloop_add(int fd, mainloop_callback_t cb, void *data)
57 {
58 struct epoll_event ev = {
59 .events = EPOLLIN,
60 };
61
62 struct mainloop_data *md;
63
64 if (fd >= nrhandler) {
65 mds = realloc(mds, sizeof(*mds) * (fd + 1));
66 if (!mds)
67 return -1;
68 nrhandler = fd + 1;
69 }
70
71 md = malloc(sizeof(*md));
72 if (!md)
73 return -1;
74
75 md->data = data;
76 md->cb = cb;
77 md->fd = fd;
78
79 mds[fd] = md;
80 ev.data.ptr = md;
81
82 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
83 free(md);
84 return -1;
85 }
86
87 return 0;
88 }
89
mainloop_del(int fd)90 int mainloop_del(int fd)
91 {
92 if (fd >= nrhandler)
93 return -1;
94
95 if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
96 return -1;
97
98 free(mds[fd]);
99
100 return 0;
101 }
102
mainloop_init(void)103 int mainloop_init(void)
104 {
105 epfd = epoll_create(2);
106 if (epfd < 0)
107 return -1;
108
109 return 0;
110 }
111
mainloop_exit(void)112 void mainloop_exit(void)
113 {
114 exit_mainloop = 1;
115 }
116
mainloop_fini(void)117 void mainloop_fini(void)
118 {
119 close(epfd);
120 }
121