root/tools/thermal/lib/mainloop.c
// 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 sig_atomic_t exit_mainloop;

struct mainloop_data {
        mainloop_callback_t cb;
        void *data;
        int fd;
};

#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;

        md = malloc(sizeof(*md));
        if (!md)
                return -1;

        md->data = data;
        md->cb = cb;
        md->fd = fd;

        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 (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
                return -1;

        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);
}