Blame axfer/waiter-epoll.c

Packit Service a9274b
// SPDX-License-Identifier: GPL-2.0
Packit Service a9274b
//
Packit Service a9274b
// waiter-epoll.c - Waiter for event notification by epoll(7).
Packit Service a9274b
//
Packit Service a9274b
// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp>
Packit Service a9274b
//
Packit Service a9274b
// Licensed under the terms of the GNU General Public License, version 2.
Packit Service a9274b
Packit Service a9274b
#include "waiter.h"
Packit Service a9274b
#include "misc.h"
Packit Service a9274b
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <unistd.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
#include <sys/types.h>
Packit Service a9274b
#include <sys/epoll.h>
Packit Service a9274b
Packit Service a9274b
struct epoll_state {
Packit Service a9274b
	int epfd;
Packit Service a9274b
	struct epoll_event *events;
Packit Service a9274b
	unsigned int ev_count;
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static int epoll_prepare(struct waiter_context *waiter)
Packit Service a9274b
{
Packit Service a9274b
	struct epoll_state *state = waiter->private_data;
Packit Service a9274b
	int i;
Packit Service a9274b
Packit Service a9274b
	state->ev_count = waiter->pfd_count;
Packit Service a9274b
	state->events = calloc(state->ev_count, sizeof(*state->events));
Packit Service a9274b
	if (state->events == NULL)
Packit Service a9274b
		return -ENOMEM;
Packit Service a9274b
Packit Service a9274b
	state->epfd = epoll_create(1);
Packit Service a9274b
	if (state->epfd < 0)
Packit Service a9274b
		return -errno;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < waiter->pfd_count; ++i) {
Packit Service a9274b
		struct epoll_event ev = {
Packit Service a9274b
			.data.fd = waiter->pfds[i].fd,
Packit Service a9274b
			.events = waiter->pfds[i].events,
Packit Service a9274b
		};
Packit Service a9274b
		if (epoll_ctl(state->epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0)
Packit Service a9274b
			return -errno;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static int epoll_wait_event(struct waiter_context *waiter, int timeout_msec)
Packit Service a9274b
{
Packit Service a9274b
	struct epoll_state *state = waiter->private_data;
Packit Service a9274b
	unsigned int ev_count;
Packit Service a9274b
	int i, j;
Packit Service a9274b
	int err;
Packit Service a9274b
Packit Service a9274b
	memset(state->events, 0, state->ev_count * sizeof(*state->events));
Packit Service a9274b
	err = epoll_wait(state->epfd, state->events, state->ev_count,
Packit Service a9274b
			 timeout_msec);
Packit Service a9274b
	if (err < 0)
Packit Service a9274b
		return -errno;
Packit Service a9274b
	ev_count = (unsigned int)err;
Packit Service a9274b
Packit Service a9274b
	if (ev_count > 0) {
Packit Service a9274b
		// Reconstruct data of pollfd structure.
Packit Service a9274b
		for (i = 0; i < ev_count; ++i) {
Packit Service a9274b
			struct epoll_event *ev = &state->events[i];
Packit Service a9274b
			for (j = 0; j < waiter->pfd_count; ++j) {
Packit Service a9274b
				if (waiter->pfds[i].fd == ev->data.fd) {
Packit Service a9274b
					waiter->pfds[i].revents = ev->events;
Packit Service a9274b
					break;
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	return ev_count;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void epoll_release(struct waiter_context *waiter)
Packit Service a9274b
{
Packit Service a9274b
	struct epoll_state *state = waiter->private_data;
Packit Service a9274b
	int i;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < waiter->pfd_count; ++i) {
Packit Service a9274b
		int fd = waiter->pfds[i].fd;
Packit Service a9274b
		epoll_ctl(state->epfd, EPOLL_CTL_DEL, fd, NULL);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	free(state->events);
Packit Service a9274b
	state->events = NULL;
Packit Service a9274b
Packit Service a9274b
	close(state->epfd);
Packit Service a9274b
Packit Service a9274b
	state->ev_count = 0;
Packit Service a9274b
	state->epfd = 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
const struct waiter_data waiter_epoll = {
Packit Service a9274b
	.ops = {
Packit Service a9274b
		.prepare	= epoll_prepare,
Packit Service a9274b
		.wait_event	= epoll_wait_event,
Packit Service a9274b
		.release	= epoll_release,
Packit Service a9274b
	},
Packit Service a9274b
	.private_size = sizeof(struct epoll_state),
Packit Service a9274b
};