ble_gatt_client
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
mainloop.c
Go to the documentation of this file.
1 
10 /*
11  *
12  * BlueZ - Bluetooth protocol stack for Linux
13  *
14  * Copyright (C) 2011-2014 Intel Corporation
15  * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
16  *
17  *
18  * This library is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU Lesser General Public
20  * License as published by the Free Software Foundation; either
21  * version 2.1 of the License, or (at your option) any later version.
22  *
23  * This library is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26  * Lesser General Public License for more details.
27  *
28  * You should have received a copy of the GNU Lesser General Public
29  * License along with this library; if not, write to the Free Software
30  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31  *
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37 
38 #include <stdio.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <signal.h>
44 #include <sys/signalfd.h>
45 #include <sys/timerfd.h>
46 #include <sys/epoll.h>
47 
48 #include "mainloop.h"
49 
50 #define MAX_EPOLL_EVENTS 10
51 
52 static int epoll_fd;
53 static int epoll_terminate;
54 static int exit_status;
55 
59 struct mainloop_data {
61  int fd;
63  uint32_t events;
69  void *user_data;
70 };
71 
72 #define MAX_MAINLOOP_ENTRIES 128
73 
78 
79 struct timeout_data {
80  int fd;
83  void *user_data;
84 };
85 
86 struct signal_data {
87  int fd;
88  sigset_t mask;
91  void *user_data;
92 };
93 
94 static struct signal_data *signal_data;
95 
101 void mainloop_init(void)
102 {
103  unsigned int i;
104 
105  epoll_fd = epoll_create1(EPOLL_CLOEXEC);
106 
107  for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)
108  mainloop_list[i] = NULL;
109 
110  epoll_terminate = 0;
111 }
112 
116 void mainloop_quit(void)
117 {
118  epoll_terminate = 1;
119 }
120 
126 {
127  exit_status = EXIT_SUCCESS;
128  epoll_terminate = 1;
129 }
130 
136 {
137  exit_status = EXIT_FAILURE;
138  epoll_terminate = 1;
139 }
140 
147 static void signal_callback(int fd, uint32_t events, void *user_data)
148 {
149  struct signal_data *data = user_data;
150  struct signalfd_siginfo si;
151  ssize_t result;
152 
153  if (events & (EPOLLERR | EPOLLHUP)) {
154  mainloop_quit();
155  return;
156  }
157 
158  result = read(fd, &si, sizeof(si));
159  if (result != sizeof(si))
160  return;
161 
162  if (data->callback)
163  data->callback(si.ssi_signo, data->user_data);
164 }
165 
174 int mainloop_run(void)
175 {
176  unsigned int i;
177 
178  if (signal_data) {
179  if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
180  return EXIT_FAILURE;
181 
182  signal_data->fd = signalfd(-1, &signal_data->mask,
183  SFD_NONBLOCK | SFD_CLOEXEC);
184  if (signal_data->fd < 0)
185  return EXIT_FAILURE;
186 
187  if (mainloop_add_fd(signal_data->fd, EPOLLIN,
188  signal_callback, signal_data, NULL) < 0) {
189  close(signal_data->fd);
190  return EXIT_FAILURE;
191  }
192  }
193 
194  exit_status = EXIT_SUCCESS;
195 
196  while (!epoll_terminate) {
197  struct epoll_event events[MAX_EPOLL_EVENTS];
198  int n, nfds;
199 
200  nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
201  if (nfds < 0)
202  continue;
203 
204  for (n = 0; n < nfds; n++) {
205  struct mainloop_data *data = events[n].data.ptr;
206 
207  data->callback(data->fd, events[n].events,
208  data->user_data);
209  }
210  }
211 
212  if (signal_data) {
213  mainloop_remove_fd(signal_data->fd);
214  close(signal_data->fd);
215 
216  if (signal_data->destroy)
217  signal_data->destroy(signal_data->user_data);
218  }
219 
220  for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {
221  struct mainloop_data *data = mainloop_list[i];
222 
223  mainloop_list[i] = NULL;
224 
225  if (data) {
226  epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
227 
228  if (data->destroy)
229  data->destroy(data->user_data);
230 
231  free(data);
232  }
233  }
234 
235  close(epoll_fd);
236  epoll_fd = 0;
237 
238  return exit_status;
239 }
240 
254 {
255  struct mainloop_data *data;
256  struct epoll_event ev;
257  int err;
258 
259  if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)
260  return -EINVAL;
261 
262  data = malloc(sizeof(*data));
263  if (!data)
264  return -ENOMEM;
265 
266  memset(data, 0, sizeof(*data));
267  data->fd = fd;
268  data->events = events;
269  data->callback = callback;
270  data->destroy = destroy;
271  data->user_data = user_data;
272 
273  memset(&ev, 0, sizeof(ev));
274  ev.events = events;
275  ev.data.ptr = data;
276 
277  err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);
278  if (err < 0) {
279  free(data);
280  return err;
281  }
282 
283  mainloop_list[fd] = data;
284 
285  return 0;
286 }
287 
296 int mainloop_modify_fd(int fd, uint32_t events)
297 {
298  struct mainloop_data *data;
299  struct epoll_event ev;
300  int err;
301 
302  if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
303  return -EINVAL;
304 
305  data = mainloop_list[fd];
306  if (!data)
307  return -ENXIO;
308 
309  memset(&ev, 0, sizeof(ev));
310  ev.events = events;
311  ev.data.ptr = data;
312 
313  err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
314  if (err < 0)
315  return err;
316 
317  data->events = events;
318 
319  return 0;
320 }
321 
323 {
324  struct mainloop_data *data;
325  int err;
326 
327  if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
328  return -EINVAL;
329 
330  data = mainloop_list[fd];
331  if (!data)
332  return -ENXIO;
333 
334  mainloop_list[fd] = NULL;
335 
336  err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
337 
338  if (data->destroy)
339  data->destroy(data->user_data);
340 
341  free(data);
342 
343  return err;
344 }
345 
346 static void timeout_destroy(void *user_data)
347 {
348  struct timeout_data *data = user_data;
349 
350  close(data->fd);
351  data->fd = -1;
352 
353  if (data->destroy)
354  data->destroy(data->user_data);
355 }
356 
357 static void timeout_callback(int fd, uint32_t events, void *user_data)
358 {
359  struct timeout_data *data = user_data;
360  uint64_t expired;
361  ssize_t result;
362 
363  if (events & (EPOLLERR | EPOLLHUP))
364  return;
365 
366  result = read(data->fd, &expired, sizeof(expired));
367  if (result != sizeof(expired))
368  return;
369 
370  if (data->callback)
371  data->callback(data->fd, data->user_data);
372 }
373 
374 static inline int timeout_set(int fd, unsigned int msec)
375 {
376  struct itimerspec itimer;
377  unsigned int sec = msec / 1000;
378 
379  memset(&itimer, 0, sizeof(itimer));
380  itimer.it_interval.tv_sec = 0;
381  itimer.it_interval.tv_nsec = 0;
382  itimer.it_value.tv_sec = sec;
383  itimer.it_value.tv_nsec = (msec - (sec * 1000)) * 1000;
384 
385  return timerfd_settime(fd, 0, &itimer, NULL);
386 }
387 
388 int mainloop_add_timeout(unsigned int msec, mainloop_timeout_func callback,
389  void *user_data, mainloop_destroy_func destroy)
390 {
391  struct timeout_data *data;
392 
393  if (!callback)
394  return -EINVAL;
395 
396  data = malloc(sizeof(*data));
397  if (!data)
398  return -ENOMEM;
399 
400  memset(data, 0, sizeof(*data));
401  data->callback = callback;
402  data->destroy = destroy;
403  data->user_data = user_data;
404 
405  data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
406  if (data->fd < 0) {
407  free(data);
408  return -EIO;
409  }
410 
411  if (msec > 0) {
412  if (timeout_set(data->fd, msec) < 0) {
413  close(data->fd);
414  free(data);
415  return -EIO;
416  }
417  }
418 
419  if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
420  timeout_callback, data, timeout_destroy) < 0) {
421  close(data->fd);
422  free(data);
423  return -EIO;
424  }
425 
426  return data->fd;
427 }
428 
429 int mainloop_modify_timeout(int id, unsigned int msec)
430 {
431  if (msec > 0) {
432  if (timeout_set(id, msec) < 0)
433  return -EIO;
434  }
435 
436  if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
437  return -EIO;
438 
439  return 0;
440 }
441 
443 {
444  return mainloop_remove_fd(id);
445 }
446 
459 {
460  struct signal_data *data;
461 
462  if (!mask || !callback)
463  return -EINVAL;
464 
465  data = malloc(sizeof(*data));
466  if (!data)
467  return -ENOMEM;
468 
469  memset(data, 0, sizeof(*data));
470  data->callback = callback;
471  data->destroy = destroy;
472  data->user_data = user_data;
473 
474  data->fd = -1;
475  memcpy(&data->mask, mask, sizeof(sigset_t));
476 
477  free(signal_data);
478  signal_data = data;
479 
480  return 0;
481 }
mainloop_signal_func callback
Definition: mainloop.c:89
#define MAX_MAINLOOP_ENTRIES
Definition: mainloop.c:72
int mainloop_add_timeout(unsigned int msec, mainloop_timeout_func callback, void *user_data, mainloop_destroy_func destroy)
Definition: mainloop.c:388
int mainloop_remove_timeout(int id)
Definition: mainloop.c:442
void mainloop_exit_failure(void)
Definition: mainloop.c:135
int mainloop_run(void)
Definition: mainloop.c:174
void mainloop_quit(void)
Definition: mainloop.c:116
static int exit_status
Definition: mainloop.c:54
void(* mainloop_timeout_func)(int id, void *user_data)
Definition: mainloop.h:31
static int timeout_set(int fd, unsigned int msec)
Definition: mainloop.c:374
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback, void *user_data, mainloop_destroy_func destroy)
Definition: mainloop.c:457
int fd
socket or file descriptor, incl. standard i/o
Definition: mainloop.c:61
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback, void *user_data, mainloop_destroy_func destroy)
Definition: mainloop.c:252
void mainloop_init(void)
Definition: mainloop.c:101
static void timeout_callback(int fd, uint32_t events, void *user_data)
Definition: mainloop.c:357
int mainloop_remove_fd(int fd)
Definition: mainloop.c:322
mainloop_destroy_func destroy
data management call back function(void *user_data);
Definition: mainloop.c:67
void * user_data
Definition: mainloop.c:83
void(* mainloop_event_func)(int fd, uint32_t events, void *user_data)
Definition: mainloop.h:30
mainloop_timeout_func callback
Definition: mainloop.c:81
int mainloop_modify_fd(int fd, uint32_t events)
Definition: mainloop.c:296
void(* mainloop_signal_func)(int signum, void *user_data)
Definition: mainloop.h:32
uint32_t events
epoll event
Definition: mainloop.c:63
static void signal_callback(int fd, uint32_t events, void *user_data)
Definition: mainloop.c:147
int mainloop_modify_timeout(int id, unsigned int msec)
Definition: mainloop.c:429
sigset_t mask
Definition: mainloop.c:88
static struct signal_data * signal_data
Definition: mainloop.c:94
void * user_data
Definition: mainloop.c:91
mainloop file descriptor event data structure
Definition: mainloop.c:59
mainloop_destroy_func destroy
Definition: mainloop.c:90
static int epoll_terminate
Definition: mainloop.c:53
static struct mainloop_data * mainloop_list[MAX_MAINLOOP_ENTRIES]
array of file descriptor event stub
Definition: mainloop.c:77
mainloop_destroy_func destroy
Definition: mainloop.c:82
static int epoll_fd
Definition: mainloop.c:52
mainloop_event_func callback
call back function(int fd, uint32_t events, void *user_data);
Definition: mainloop.c:65
static void timeout_destroy(void *user_data)
Definition: mainloop.c:346
void mainloop_exit_success(void)
Definition: mainloop.c:125
void(* mainloop_destroy_func)(void *user_data)
Definition: mainloop.h:28
void * user_data
pointer to a user specific data structure
Definition: mainloop.c:69