Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/hcitools/monitor/mainloop.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2011-2012 Intel Corporation5* Copyright (C) 2002-2010 Marcel Holtmann <[email protected]>6*7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21*22*/2324#ifdef HAVE_CONFIG_H25#include <config.h>26#endif2728#include <stdio.h>29#include <errno.h>30#include <unistd.h>31#include <stdlib.h>32#include <string.h>33#include <signal.h>34#include <sys/signalfd.h>35#include <sys/timerfd.h>36#include <sys/epoll.h>3738#include "mainloop.h"3940#define MAX_EPOLL_EVENTS 104142static int epoll_fd;43static int epoll_terminate;4445struct mainloop_data {46int fd;47uint32_t events;48mainloop_event_func callback;49mainloop_destroy_func destroy;50void *user_data;51};5253#define MAX_MAINLOOP_ENTRIES 1285455static struct mainloop_data *mainloop_list[MAX_MAINLOOP_ENTRIES];5657struct timeout_data {58int fd;59mainloop_timeout_func callback;60mainloop_destroy_func destroy;61void *user_data;62};6364struct signal_data {65int fd;66sigset_t mask;67mainloop_signal_func callback;68mainloop_destroy_func destroy;69void *user_data;70};7172static struct signal_data *signal_data;7374void mainloop_init(void)75{76unsigned int i;7778epoll_fd = epoll_create1(EPOLL_CLOEXEC);7980for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)81mainloop_list[i] = NULL;8283epoll_terminate = 0;84}8586void mainloop_quit(void)87{88epoll_terminate = 1;89}9091static void signal_callback(int fd, uint32_t events, void *user_data)92{93struct signal_data *data = user_data;94struct signalfd_siginfo si;95ssize_t result;9697if (events & (EPOLLERR | EPOLLHUP)) {98mainloop_quit();99return;100}101102result = read(fd, &si, sizeof(si));103if (result != sizeof(si))104return;105106if (data->callback)107data->callback(si.ssi_signo, data->user_data);108}109110int mainloop_run(void)111{112unsigned int i;113114if (signal_data) {115if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)116return 1;117118signal_data->fd = signalfd(-1, &signal_data->mask,119SFD_NONBLOCK | SFD_CLOEXEC);120if (signal_data->fd < 0)121return 1;122123if (mainloop_add_fd(signal_data->fd, EPOLLIN,124signal_callback, signal_data, NULL) < 0) {125close(signal_data->fd);126return 1;127}128}129130while (!epoll_terminate) {131struct epoll_event events[MAX_EPOLL_EVENTS];132int n, nfds;133134nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);135if (nfds < 0)136continue;137138for (n = 0; n < nfds; n++) {139struct mainloop_data *data = events[n].data.ptr;140141data->callback(data->fd, events[n].events,142data->user_data);143}144}145146if (signal_data) {147mainloop_remove_fd(signal_data->fd);148close(signal_data->fd);149150if (signal_data->destroy)151signal_data->destroy(signal_data->user_data);152}153154for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {155struct mainloop_data *data = mainloop_list[i];156157mainloop_list[i] = NULL;158159if (data) {160epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);161162if (data->destroy)163data->destroy(data->user_data);164165free(data);166}167}168169close(epoll_fd);170epoll_fd = 0;171172return 0;173}174175int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,176void *user_data, mainloop_destroy_func destroy)177{178struct mainloop_data *data;179struct epoll_event ev;180int err;181182if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)183return -EINVAL;184185data = malloc(sizeof(*data));186if (!data)187return -ENOMEM;188189memset(data, 0, sizeof(*data));190data->fd = fd;191data->events = events;192data->callback = callback;193data->destroy = destroy;194data->user_data = user_data;195196memset(&ev, 0, sizeof(ev));197ev.events = events;198ev.data.ptr = data;199200err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);201if (err < 0) {202free(data);203return err;204}205206mainloop_list[fd] = data;207208return 0;209}210211int mainloop_modify_fd(int fd, uint32_t events)212{213struct mainloop_data *data;214struct epoll_event ev;215int err;216217if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)218return -EINVAL;219220data = mainloop_list[fd];221if (!data)222return -ENXIO;223224if (data->events == events)225return 0;226227memset(&ev, 0, sizeof(ev));228ev.events = events;229ev.data.ptr = data;230231err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);232if (err < 0)233return err;234235data->events = events;236237return 0;238}239240int mainloop_remove_fd(int fd)241{242struct mainloop_data *data;243int err;244245if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)246return -EINVAL;247248data = mainloop_list[fd];249if (!data)250return -ENXIO;251252mainloop_list[fd] = NULL;253254err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);255256if (data->destroy)257data->destroy(data->user_data);258259free(data);260261return err;262}263264static void timeout_destroy(void *user_data)265{266struct timeout_data *data = user_data;267268close(data->fd);269data->fd = -1;270271if (data->destroy)272data->destroy(data->user_data);273}274275static void timeout_callback(int fd, uint32_t events, void *user_data)276{277struct timeout_data *data = user_data;278uint64_t expired;279ssize_t result;280281if (events & (EPOLLERR | EPOLLHUP))282return;283284result = read(data->fd, &expired, sizeof(expired));285if (result != sizeof(expired))286return;287288if (data->callback)289data->callback(data->fd, data->user_data);290}291292static inline int timeout_set(int fd, unsigned int seconds)293{294struct itimerspec itimer;295296memset(&itimer, 0, sizeof(itimer));297itimer.it_interval.tv_sec = 0;298itimer.it_interval.tv_nsec = 0;299itimer.it_value.tv_sec = seconds;300itimer.it_value.tv_nsec = 0;301302return timerfd_settime(fd, 0, &itimer, NULL);303}304305int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,306void *user_data, mainloop_destroy_func destroy)307{308struct timeout_data *data;309310if (!callback)311return -EINVAL;312313data = malloc(sizeof(*data));314if (!data)315return -ENOMEM;316317memset(data, 0, sizeof(*data));318data->callback = callback;319data->destroy = destroy;320data->user_data = user_data;321322data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);323if (data->fd < 0) {324free(data);325return -EIO;326}327328if (seconds > 0) {329if (timeout_set(data->fd, seconds) < 0) {330close(data->fd);331free(data);332return -EIO;333}334}335336if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,337timeout_callback, data, timeout_destroy) < 0) {338close(data->fd);339free(data);340return -EIO;341}342343return data->fd;344}345346int mainloop_modify_timeout(int id, unsigned int seconds)347{348if (seconds > 0) {349if (timeout_set(id, seconds) < 0)350return -EIO;351}352353if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)354return -EIO;355356return 0;357}358359int mainloop_remove_timeout(int id)360{361return mainloop_remove_fd(id);362}363364int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,365void *user_data, mainloop_destroy_func destroy)366{367struct signal_data *data;368369if (!mask || !callback)370return -EINVAL;371372data = malloc(sizeof(*data));373if (!data)374return -ENOMEM;375376memset(data, 0, sizeof(*data));377data->callback = callback;378data->destroy = destroy;379data->user_data = user_data;380381data->fd = -1;382memcpy(&data->mask, mask, sizeof(sigset_t));383384free(signal_data);385signal_data = data;386387return 0;388}389390391