3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011-2012 Intel Corporation
6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program 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
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; 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 if (data->events == events)
228 memset(&ev, 0, sizeof(ev));
232 err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
236 data->events = events;
241 int mainloop_remove_fd(int fd)
243 struct mainloop_data *data;
246 if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
249 data = mainloop_list[fd];
253 mainloop_list[fd] = NULL;
255 err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
258 data->destroy(data->user_data);
265 static void timeout_destroy(void *user_data)
267 struct timeout_data *data = user_data;
273 data->destroy(data->user_data);
276 static void timeout_callback(int fd, uint32_t events, void *user_data)
278 struct timeout_data *data = user_data;
282 if (events & (EPOLLERR | EPOLLHUP))
285 result = read(data->fd, &expired, sizeof(expired));
286 if (result != sizeof(expired))
290 data->callback(data->fd, data->user_data);
293 static inline int timeout_set(int fd, unsigned int seconds)
295 struct itimerspec itimer;
297 memset(&itimer, 0, sizeof(itimer));
298 itimer.it_interval.tv_sec = 0;
299 itimer.it_interval.tv_nsec = 0;
300 itimer.it_value.tv_sec = seconds;
301 itimer.it_value.tv_nsec = 0;
303 return timerfd_settime(fd, 0, &itimer, NULL);
306 int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
307 void *user_data, mainloop_destroy_func destroy)
309 struct timeout_data *data;
314 data = malloc(sizeof(*data));
318 memset(data, 0, sizeof(*data));
319 data->callback = callback;
320 data->destroy = destroy;
321 data->user_data = user_data;
323 data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
330 if (timeout_set(data->fd, seconds) < 0) {
337 if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
338 timeout_callback, data, timeout_destroy) < 0) {
347 int mainloop_modify_timeout(int id, unsigned int seconds)
350 if (timeout_set(id, seconds) < 0)
354 if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
360 int mainloop_remove_timeout(int id)
362 return mainloop_remove_fd(id);
365 int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
366 void *user_data, mainloop_destroy_func destroy)
368 struct signal_data *data;
370 if (!mask || !callback)
373 data = malloc(sizeof(*data));
377 memset(data, 0, sizeof(*data));
378 data->callback = callback;
379 data->destroy = destroy;
380 data->user_data = user_data;
383 memcpy(&data->mask, mask, sizeof(sigset_t));