162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1+ 262306a36Sopenharmony_ci// Copyright (C) 2022, Linaro Ltd - Daniel Lezcano <daniel.lezcano@linaro.org> 362306a36Sopenharmony_ci#include <stdlib.h> 462306a36Sopenharmony_ci#include <errno.h> 562306a36Sopenharmony_ci#include <unistd.h> 662306a36Sopenharmony_ci#include <signal.h> 762306a36Sopenharmony_ci#include <sys/epoll.h> 862306a36Sopenharmony_ci#include "mainloop.h" 962306a36Sopenharmony_ci#include "log.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic int epfd = -1; 1262306a36Sopenharmony_cistatic unsigned short nrhandler; 1362306a36Sopenharmony_cistatic sig_atomic_t exit_mainloop; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct mainloop_data { 1662306a36Sopenharmony_ci mainloop_callback_t cb; 1762306a36Sopenharmony_ci void *data; 1862306a36Sopenharmony_ci int fd; 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct mainloop_data **mds; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define MAX_EVENTS 10 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciint mainloop(unsigned int timeout) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci int i, nfds; 2862306a36Sopenharmony_ci struct epoll_event events[MAX_EVENTS]; 2962306a36Sopenharmony_ci struct mainloop_data *md; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (epfd < 0) 3262306a36Sopenharmony_ci return -1; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci for (;;) { 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (exit_mainloop || !nfds) 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (nfds < 0) { 4262306a36Sopenharmony_ci if (errno == EINTR) 4362306a36Sopenharmony_ci continue; 4462306a36Sopenharmony_ci return -1; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci for (i = 0; i < nfds; i++) { 4862306a36Sopenharmony_ci md = events[i].data.ptr; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (md->cb(md->fd, md->data) > 0) 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint mainloop_add(int fd, mainloop_callback_t cb, void *data) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct epoll_event ev = { 5962306a36Sopenharmony_ci .events = EPOLLIN, 6062306a36Sopenharmony_ci }; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci struct mainloop_data *md; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (fd >= nrhandler) { 6562306a36Sopenharmony_ci mds = realloc(mds, sizeof(*mds) * (fd + 1)); 6662306a36Sopenharmony_ci if (!mds) 6762306a36Sopenharmony_ci return -1; 6862306a36Sopenharmony_ci nrhandler = fd + 1; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci md = malloc(sizeof(*md)); 7262306a36Sopenharmony_ci if (!md) 7362306a36Sopenharmony_ci return -1; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci md->data = data; 7662306a36Sopenharmony_ci md->cb = cb; 7762306a36Sopenharmony_ci md->fd = fd; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci mds[fd] = md; 8062306a36Sopenharmony_ci ev.data.ptr = md; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { 8362306a36Sopenharmony_ci free(md); 8462306a36Sopenharmony_ci return -1; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciint mainloop_del(int fd) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci if (fd >= nrhandler) 9362306a36Sopenharmony_ci return -1; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0) 9662306a36Sopenharmony_ci return -1; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci free(mds[fd]); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciint mainloop_init(void) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci epfd = epoll_create(2); 10662306a36Sopenharmony_ci if (epfd < 0) 10762306a36Sopenharmony_ci return -1; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_civoid mainloop_exit(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci exit_mainloop = 1; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_civoid mainloop_fini(void) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci close(epfd); 12062306a36Sopenharmony_ci} 121