1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// waiter-select.c - Waiter for event notification by select(2). 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 11c72fcc34Sopenharmony_ci#include <stdlib.h> 12c72fcc34Sopenharmony_ci#include <unistd.h> 13c72fcc34Sopenharmony_ci#include <string.h> 14c72fcc34Sopenharmony_ci#include <errno.h> 15c72fcc34Sopenharmony_ci#include <sys/select.h> 16c72fcc34Sopenharmony_ci 17c72fcc34Sopenharmony_ci// Except for POLLERR. 18c72fcc34Sopenharmony_ci#ifdef POLLRDNORM 19c72fcc34Sopenharmony_ci// This program is for userspace compliant to POSIX 2008 (IEEE 1003.1:2008). 20c72fcc34Sopenharmony_ci// This is the default compliance level since glibc-2.12 or later. 21c72fcc34Sopenharmony_ci# define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP) 22c72fcc34Sopenharmony_ci# define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT) 23c72fcc34Sopenharmony_ci#else 24c72fcc34Sopenharmony_ci// However it's allowed to be for old compliance levels. 25c72fcc34Sopenharmony_ci# define POLLIN_SET (POLLIN | POLLHUP) 26c72fcc34Sopenharmony_ci# define POLLOUT_SET (POLLOUT) 27c72fcc34Sopenharmony_ci#endif 28c72fcc34Sopenharmony_ci#define POLLEX_SET (POLLPRI) 29c72fcc34Sopenharmony_ci 30c72fcc34Sopenharmony_ci 31c72fcc34Sopenharmony_cistruct select_state { 32c72fcc34Sopenharmony_ci fd_set rfds_rd; 33c72fcc34Sopenharmony_ci fd_set rfds_wr; 34c72fcc34Sopenharmony_ci fd_set rfds_ex; 35c72fcc34Sopenharmony_ci}; 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_cistatic int select_prepare(struct waiter_context *waiter ATTRIBUTE_UNUSED) 38c72fcc34Sopenharmony_ci{ 39c72fcc34Sopenharmony_ci return 0; 40c72fcc34Sopenharmony_ci} 41c72fcc34Sopenharmony_ci 42c72fcc34Sopenharmony_cistatic int select_wait_event(struct waiter_context *waiter, int timeout_msec) 43c72fcc34Sopenharmony_ci{ 44c72fcc34Sopenharmony_ci struct select_state *state = waiter->private_data; 45c72fcc34Sopenharmony_ci struct pollfd *pfd; 46c72fcc34Sopenharmony_ci int fd_max; 47c72fcc34Sopenharmony_ci struct timeval tv, *tv_ptr; 48c72fcc34Sopenharmony_ci int i; 49c72fcc34Sopenharmony_ci int err; 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_ci FD_ZERO(&state->rfds_rd); 52c72fcc34Sopenharmony_ci FD_ZERO(&state->rfds_wr); 53c72fcc34Sopenharmony_ci FD_ZERO(&state->rfds_ex); 54c72fcc34Sopenharmony_ci 55c72fcc34Sopenharmony_ci fd_max = 0; 56c72fcc34Sopenharmony_ci for (i = 0; i < (int)waiter->pfd_count; ++i) { 57c72fcc34Sopenharmony_ci pfd = &waiter->pfds[i]; 58c72fcc34Sopenharmony_ci 59c72fcc34Sopenharmony_ci if (pfd->events & POLLIN_SET) 60c72fcc34Sopenharmony_ci FD_SET(pfd->fd, &state->rfds_rd); 61c72fcc34Sopenharmony_ci if (pfd->events & POLLOUT_SET) 62c72fcc34Sopenharmony_ci FD_SET(pfd->fd, &state->rfds_wr); 63c72fcc34Sopenharmony_ci if (pfd->events & POLLEX_SET) 64c72fcc34Sopenharmony_ci FD_SET(pfd->fd, &state->rfds_ex); 65c72fcc34Sopenharmony_ci if (pfd->fd > fd_max) 66c72fcc34Sopenharmony_ci fd_max = pfd->fd; 67c72fcc34Sopenharmony_ci } 68c72fcc34Sopenharmony_ci 69c72fcc34Sopenharmony_ci if (timeout_msec < 0) { 70c72fcc34Sopenharmony_ci tv_ptr = NULL; 71c72fcc34Sopenharmony_ci } else { 72c72fcc34Sopenharmony_ci tv.tv_sec = 0; 73c72fcc34Sopenharmony_ci tv.tv_usec = timeout_msec * 1000; 74c72fcc34Sopenharmony_ci tv_ptr = &tv; 75c72fcc34Sopenharmony_ci } 76c72fcc34Sopenharmony_ci 77c72fcc34Sopenharmony_ci err = select(fd_max + 1, &state->rfds_rd, &state->rfds_wr, 78c72fcc34Sopenharmony_ci &state->rfds_ex, tv_ptr); 79c72fcc34Sopenharmony_ci if (err < 0) 80c72fcc34Sopenharmony_ci return -errno; 81c72fcc34Sopenharmony_ci 82c72fcc34Sopenharmony_ci for (i = 0; i < (int)waiter->pfd_count; ++i) { 83c72fcc34Sopenharmony_ci pfd = &waiter->pfds[i]; 84c72fcc34Sopenharmony_ci 85c72fcc34Sopenharmony_ci pfd->revents = 0; 86c72fcc34Sopenharmony_ci if (FD_ISSET(pfd->fd, &state->rfds_rd)) 87c72fcc34Sopenharmony_ci pfd->revents |= POLLIN; 88c72fcc34Sopenharmony_ci if (FD_ISSET(pfd->fd, &state->rfds_wr)) 89c72fcc34Sopenharmony_ci pfd->revents |= POLLOUT; 90c72fcc34Sopenharmony_ci if (FD_ISSET(pfd->fd, &state->rfds_ex)) 91c72fcc34Sopenharmony_ci pfd->revents |= POLLHUP; 92c72fcc34Sopenharmony_ci } 93c72fcc34Sopenharmony_ci 94c72fcc34Sopenharmony_ci return err; 95c72fcc34Sopenharmony_ci} 96c72fcc34Sopenharmony_ci 97c72fcc34Sopenharmony_cistatic void select_release(struct waiter_context *waiter ATTRIBUTE_UNUSED) 98c72fcc34Sopenharmony_ci{ 99c72fcc34Sopenharmony_ci return; 100c72fcc34Sopenharmony_ci} 101c72fcc34Sopenharmony_ci 102c72fcc34Sopenharmony_ciconst struct waiter_data waiter_select = { 103c72fcc34Sopenharmony_ci .ops = { 104c72fcc34Sopenharmony_ci .prepare = select_prepare, 105c72fcc34Sopenharmony_ci .wait_event = select_wait_event, 106c72fcc34Sopenharmony_ci .release = select_release, 107c72fcc34Sopenharmony_ci }, 108c72fcc34Sopenharmony_ci .private_size = sizeof(struct select_state), 109c72fcc34Sopenharmony_ci}; 110