1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// waiter-epoll.c - Waiter for event notification by epoll(7). 4c72fcc34Sopenharmony_ci// 5c72fcc34Sopenharmony_ci// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6c72fcc34Sopenharmony_ci// 7c72fcc34Sopenharmony_ci// Licensed under the terms of the GNU General Public License, version 2. 8c72fcc34Sopenharmony_ci 9c72fcc34Sopenharmony_ci#include "waiter.h" 10c72fcc34Sopenharmony_ci#include "misc.h" 11c72fcc34Sopenharmony_ci 12c72fcc34Sopenharmony_ci#include <stdlib.h> 13c72fcc34Sopenharmony_ci#include <unistd.h> 14c72fcc34Sopenharmony_ci#include <string.h> 15c72fcc34Sopenharmony_ci#include <errno.h> 16c72fcc34Sopenharmony_ci#include <sys/types.h> 17c72fcc34Sopenharmony_ci#include <sys/epoll.h> 18c72fcc34Sopenharmony_ci 19c72fcc34Sopenharmony_cistruct epoll_state { 20c72fcc34Sopenharmony_ci int epfd; 21c72fcc34Sopenharmony_ci struct epoll_event *events; 22c72fcc34Sopenharmony_ci unsigned int ev_count; 23c72fcc34Sopenharmony_ci}; 24c72fcc34Sopenharmony_ci 25c72fcc34Sopenharmony_cistatic int epoll_prepare(struct waiter_context *waiter) 26c72fcc34Sopenharmony_ci{ 27c72fcc34Sopenharmony_ci struct epoll_state *state = waiter->private_data; 28c72fcc34Sopenharmony_ci int i; 29c72fcc34Sopenharmony_ci 30c72fcc34Sopenharmony_ci state->ev_count = waiter->pfd_count; 31c72fcc34Sopenharmony_ci state->events = calloc(state->ev_count, sizeof(*state->events)); 32c72fcc34Sopenharmony_ci if (state->events == NULL) 33c72fcc34Sopenharmony_ci return -ENOMEM; 34c72fcc34Sopenharmony_ci 35c72fcc34Sopenharmony_ci state->epfd = epoll_create(1); 36c72fcc34Sopenharmony_ci if (state->epfd < 0) 37c72fcc34Sopenharmony_ci return -errno; 38c72fcc34Sopenharmony_ci 39c72fcc34Sopenharmony_ci for (i = 0; i < (int)waiter->pfd_count; ++i) { 40c72fcc34Sopenharmony_ci struct epoll_event ev = { 41c72fcc34Sopenharmony_ci .data.fd = waiter->pfds[i].fd, 42c72fcc34Sopenharmony_ci .events = waiter->pfds[i].events, 43c72fcc34Sopenharmony_ci }; 44c72fcc34Sopenharmony_ci if (epoll_ctl(state->epfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0) 45c72fcc34Sopenharmony_ci return -errno; 46c72fcc34Sopenharmony_ci } 47c72fcc34Sopenharmony_ci 48c72fcc34Sopenharmony_ci return 0; 49c72fcc34Sopenharmony_ci} 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_cistatic int epoll_wait_event(struct waiter_context *waiter, int timeout_msec) 52c72fcc34Sopenharmony_ci{ 53c72fcc34Sopenharmony_ci struct epoll_state *state = waiter->private_data; 54c72fcc34Sopenharmony_ci unsigned int ev_count; 55c72fcc34Sopenharmony_ci int i, j; 56c72fcc34Sopenharmony_ci int err; 57c72fcc34Sopenharmony_ci 58c72fcc34Sopenharmony_ci memset(state->events, 0, state->ev_count * sizeof(*state->events)); 59c72fcc34Sopenharmony_ci err = epoll_wait(state->epfd, state->events, state->ev_count, 60c72fcc34Sopenharmony_ci timeout_msec); 61c72fcc34Sopenharmony_ci if (err < 0) 62c72fcc34Sopenharmony_ci return -errno; 63c72fcc34Sopenharmony_ci ev_count = (unsigned int)err; 64c72fcc34Sopenharmony_ci 65c72fcc34Sopenharmony_ci if (ev_count > 0) { 66c72fcc34Sopenharmony_ci // Reconstruct data of pollfd structure. 67c72fcc34Sopenharmony_ci for (i = 0; i < (int)ev_count; ++i) { 68c72fcc34Sopenharmony_ci struct epoll_event *ev = &state->events[i]; 69c72fcc34Sopenharmony_ci for (j = 0; j < (int)waiter->pfd_count; ++j) { 70c72fcc34Sopenharmony_ci if (waiter->pfds[i].fd == ev->data.fd) { 71c72fcc34Sopenharmony_ci waiter->pfds[i].revents = ev->events; 72c72fcc34Sopenharmony_ci break; 73c72fcc34Sopenharmony_ci } 74c72fcc34Sopenharmony_ci } 75c72fcc34Sopenharmony_ci } 76c72fcc34Sopenharmony_ci } 77c72fcc34Sopenharmony_ci 78c72fcc34Sopenharmony_ci return ev_count; 79c72fcc34Sopenharmony_ci} 80c72fcc34Sopenharmony_ci 81c72fcc34Sopenharmony_cistatic void epoll_release(struct waiter_context *waiter) 82c72fcc34Sopenharmony_ci{ 83c72fcc34Sopenharmony_ci struct epoll_state *state = waiter->private_data; 84c72fcc34Sopenharmony_ci int i; 85c72fcc34Sopenharmony_ci 86c72fcc34Sopenharmony_ci for (i = 0; i < (int)waiter->pfd_count; ++i) { 87c72fcc34Sopenharmony_ci int fd = waiter->pfds[i].fd; 88c72fcc34Sopenharmony_ci epoll_ctl(state->epfd, EPOLL_CTL_DEL, fd, NULL); 89c72fcc34Sopenharmony_ci } 90c72fcc34Sopenharmony_ci 91c72fcc34Sopenharmony_ci free(state->events); 92c72fcc34Sopenharmony_ci state->events = NULL; 93c72fcc34Sopenharmony_ci 94c72fcc34Sopenharmony_ci close(state->epfd); 95c72fcc34Sopenharmony_ci 96c72fcc34Sopenharmony_ci state->ev_count = 0; 97c72fcc34Sopenharmony_ci state->epfd = 0; 98c72fcc34Sopenharmony_ci} 99c72fcc34Sopenharmony_ci 100c72fcc34Sopenharmony_ciconst struct waiter_data waiter_epoll = { 101c72fcc34Sopenharmony_ci .ops = { 102c72fcc34Sopenharmony_ci .prepare = epoll_prepare, 103c72fcc34Sopenharmony_ci .wait_event = epoll_wait_event, 104c72fcc34Sopenharmony_ci .release = epoll_release, 105c72fcc34Sopenharmony_ci }, 106c72fcc34Sopenharmony_ci .private_size = sizeof(struct epoll_state), 107c72fcc34Sopenharmony_ci}; 108