3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011-2014 Intel Corporation
6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 #include <sys/signalfd.h>
36 #include <sys/timerfd.h>
37 #include <sys/epoll.h>
41 #define MAX_EPOLL_EVENTS 10
44 static int epoll_terminate;
46 struct mainloop_data {
49 mainloop_event_func callback;
50 mainloop_destroy_func destroy;
54 #define MAX_MAINLOOP_ENTRIES 128
56 static struct mainloop_data *mainloop_list[MAX_MAINLOOP_ENTRIES];
60 mainloop_timeout_func callback;
61 mainloop_destroy_func destroy;
68 mainloop_signal_func callback;
69 mainloop_destroy_func destroy;
73 static struct signal_data *signal_data;
75 void mainloop_init(void)
79 epoll_fd = epoll_create1(EPOLL_CLOEXEC);
81 for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)
82 mainloop_list[i] = NULL;
87 void mainloop_quit(void)
92 static void signal_callback(int fd, uint32_t events, void *user_data)
94 struct signal_data *data = user_data;
95 struct signalfd_siginfo si;
98 if (events & (EPOLLERR | EPOLLHUP)) {
103 result = read(fd, &si, sizeof(si));
104 if (result != sizeof(si))
108 data->callback(si.ssi_signo, data->user_data);
111 int mainloop_run(void)
116 if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
119 signal_data->fd = signalfd(-1, &signal_data->mask,
120 SFD_NONBLOCK | SFD_CLOEXEC);
121 if (signal_data->fd < 0)
124 if (mainloop_add_fd(signal_data->fd, EPOLLIN,
125 signal_callback, signal_data, NULL) < 0) {
126 close(signal_data->fd);
131 while (!epoll_terminate) {
132 struct epoll_event events[MAX_EPOLL_EVENTS];
135 nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
139 for (n = 0; n < nfds; n++) {
140 struct mainloop_data *data = events[n].data.ptr;
142 data->callback(data->fd, events[n].events,
148 mainloop_remove_fd(signal_data->fd);
149 close(signal_data->fd);
151 if (signal_data->destroy)
152 signal_data->destroy(signal_data->user_data);
155 for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {
156 struct mainloop_data *data = mainloop_list[i];
158 mainloop_list[i] = NULL;
161 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
164 data->destroy(data->user_data);
176 int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
177 void *user_data, mainloop_destroy_func destroy)
179 struct mainloop_data *data;
180 struct epoll_event ev;
183 if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)
186 data = malloc(sizeof(*data));
190 memset(data, 0, sizeof(*data));
192 data->events = events;
193 data->callback = callback;
194 data->destroy = destroy;
195 data->user_data = user_data;
197 memset(&ev, 0, sizeof(ev));
201 err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);
207 mainloop_list[fd] = data;
212 int mainloop_modify_fd(int fd, uint32_t events)
214 struct mainloop_data *data;
215 struct epoll_event ev;
218 if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
221 data = mainloop_list[fd];
225 memset(&ev, 0, sizeof(ev));
229 err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
233 data->events = events;
238 int mainloop_remove_fd(int fd)
240 struct mainloop_data *data;
243 if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
246 data = mainloop_list[fd];
250 mainloop_list[fd] = NULL;
252 err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
255 data->destroy(data->user_data);
262 static void timeout_destroy(void *user_data)
264 struct timeout_data *data = user_data;
270 data->destroy(data->user_data);
273 static void timeout_callback(int fd, uint32_t events, void *user_data)
275 struct timeout_data *data = user_data;
279 if (events & (EPOLLERR | EPOLLHUP))
282 result = read(data->fd, &expired, sizeof(expired));
283 if (result != sizeof(expired))
287 data->callback(data->fd, data->user_data);
290 static inline int timeout_set(int fd, unsigned int msec)
292 struct itimerspec itimer;
293 unsigned int sec = msec / 1000;
295 memset(&itimer, 0, sizeof(itimer));
296 itimer.it_interval.tv_sec = 0;
297 itimer.it_interval.tv_nsec = 0;
298 itimer.it_value.tv_sec = sec;
299 itimer.it_value.tv_nsec = (msec - (sec * 1000)) * 1000;
301 return timerfd_settime(fd, 0, &itimer, NULL);
304 int mainloop_add_timeout(unsigned int msec, mainloop_timeout_func callback,
305 void *user_data, mainloop_destroy_func destroy)
307 struct timeout_data *data;
312 data = malloc(sizeof(*data));
316 memset(data, 0, sizeof(*data));
317 data->callback = callback;
318 data->destroy = destroy;
319 data->user_data = user_data;
321 data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
328 if (timeout_set(data->fd, msec) < 0) {
335 if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
336 timeout_callback, data, timeout_destroy) < 0) {
345 int mainloop_modify_timeout(int id, unsigned int msec)
348 if (timeout_set(id, msec) < 0)
352 if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
358 int mainloop_remove_timeout(int id)
360 return mainloop_remove_fd(id);
363 int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
364 void *user_data, mainloop_destroy_func destroy)
366 struct signal_data *data;
368 if (!mask || !callback)
371 data = malloc(sizeof(*data));
375 memset(data, 0, sizeof(*data));
376 data->callback = callback;
377 data->destroy = destroy;
378 data->user_data = user_data;
381 memcpy(&data->mask, mask, sizeof(sigset_t));