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