// SPDX-License-Identifier: LGPL-2.1+ | |
// Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> | |
#include <stdlib.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <signal.h> | |
#include <sys/epoll.h> | |
#include "mainloop.h" | |
#include "log.h" | |
static int epfd = -1; | |
static unsigned short nrhandler; | |
static sig_atomic_t exit_mainloop; | |
struct mainloop_data { | |
mainloop_callback_t cb; | |
void *data; | |
int fd; | |
}; | |
static struct mainloop_data **mds; | |
#define MAX_EVENTS 10 | |
int mainloop(unsigned int timeout) | |
{ | |
int i, nfds; | |
struct epoll_event events[MAX_EVENTS]; | |
struct mainloop_data *md; | |
if (epfd < 0) | |
return -1; | |
for (;;) { | |
nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout); | |
if (exit_mainloop || !nfds) | |
return 0; | |
if (nfds < 0) { | |
if (errno == EINTR) | |
continue; | |
return -1; | |
} | |
for (i = 0; i < nfds; i++) { | |
md = events[i].data.ptr; | |
if (md->cb(md->fd, md->data) > 0) | |
return 0; | |
} | |
} | |
} | |
int mainloop_add(int fd, mainloop_callback_t cb, void *data) | |
{ | |
struct epoll_event ev = { | |
.events = EPOLLIN, | |
}; | |
struct mainloop_data *md; | |
if (fd >= nrhandler) { | |
mds = realloc(mds, sizeof(*mds) * (fd + 1)); | |
if (!mds) | |
return -1; | |
nrhandler = fd + 1; | |
} | |
md = malloc(sizeof(*md)); | |
if (!md) | |
return -1; | |
md->data = data; | |
md->cb = cb; | |
md->fd = fd; | |
mds[fd] = md; | |
ev.data.ptr = md; | |
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { | |
free(md); | |
return -1; | |
} | |
return 0; | |
} | |
int mainloop_del(int fd) | |
{ | |
if (fd >= nrhandler) | |
return -1; | |
if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0) | |
return -1; | |
free(mds[fd]); | |
return 0; | |
} | |
int mainloop_init(void) | |
{ | |
epfd = epoll_create(2); | |
if (epfd < 0) | |
return -1; | |
return 0; | |
} | |
void mainloop_exit(void) | |
{ | |
exit_mainloop = 1; | |
} | |
void mainloop_fini(void) | |
{ | |
close(epfd); | |
} |