Blame test/poll-v-poll.c

Packit d3489f
/* SPDX-License-Identifier: MIT */
Packit d3489f
/*
Packit d3489f
 * Description: test io_uring poll handling
Packit d3489f
 *
Packit d3489f
 */
Packit d3489f
#include <errno.h>
Packit d3489f
#include <stdio.h>
Packit d3489f
#include <unistd.h>
Packit d3489f
#include <stdlib.h>
Packit d3489f
#include <string.h>
Packit d3489f
#include <signal.h>
Packit d3489f
#include <fcntl.h>
Packit d3489f
#include <sys/poll.h>
Packit d3489f
#include <sys/wait.h>
Packit d3489f
#include <sys/select.h>
Packit d3489f
#include <pthread.h>
Packit d3489f
#include <sys/epoll.h>
Packit d3489f
Packit d3489f
#include "liburing.h"
Packit d3489f
Packit d3489f
struct thread_data {
Packit d3489f
	struct io_uring *ring;
Packit d3489f
	int fd;
Packit d3489f
	int events;
Packit d3489f
	const char *test;
Packit d3489f
	int out[2];
Packit d3489f
};
Packit d3489f
Packit d3489f
static void *epoll_wait_fn(void *data)
Packit d3489f
{
Packit d3489f
	struct thread_data *td = data;
Packit d3489f
	struct epoll_event ev;
Packit d3489f
Packit d3489f
	if (epoll_wait(td->fd, &ev, 1, -1) < 0) {
Packit d3489f
		perror("epoll_wait");
Packit d3489f
		goto err;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return NULL;
Packit d3489f
err:
Packit d3489f
	return (void *) 1;
Packit d3489f
}
Packit d3489f
Packit d3489f
static void *iou_poll(void *data)
Packit d3489f
{
Packit d3489f
	struct thread_data *td = data;
Packit d3489f
	struct io_uring_sqe *sqe;
Packit d3489f
	struct io_uring_cqe *cqe;
Packit d3489f
	int ret;
Packit d3489f
Packit d3489f
	sqe = io_uring_get_sqe(td->ring);
Packit d3489f
	io_uring_prep_poll_add(sqe, td->fd, td->events);
Packit d3489f
Packit d3489f
	ret = io_uring_submit(td->ring);
Packit d3489f
	if (ret != 1) {
Packit d3489f
		fprintf(stderr, "submit got %d\n", ret);
Packit d3489f
		goto err;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = io_uring_wait_cqe(td->ring, &cqe);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "wait_cqe: %d\n", ret);
Packit d3489f
		goto err;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	td->out[0] = cqe->res & 0x3f;
Packit d3489f
	io_uring_cqe_seen(td->ring, cqe);
Packit d3489f
	return NULL;
Packit d3489f
err:
Packit d3489f
	return (void *) 1;
Packit d3489f
}
Packit d3489f
Packit d3489f
static void *poll_pipe(void *data)
Packit d3489f
{
Packit d3489f
	struct thread_data *td = data;
Packit d3489f
	struct pollfd pfd;
Packit d3489f
	int ret;
Packit d3489f
Packit d3489f
	pfd.fd = td->fd;
Packit d3489f
	pfd.events = td->events;
Packit d3489f
Packit d3489f
	ret = poll(&pfd, 1, -1);
Packit d3489f
	if (ret < 0)
Packit d3489f
		perror("poll");
Packit d3489f
Packit d3489f
	td->out[1] = pfd.revents;
Packit d3489f
	return NULL;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int do_pipe_pollin_test(struct io_uring *ring)
Packit d3489f
{
Packit d3489f
	struct thread_data td;
Packit d3489f
	pthread_t threads[2];
Packit d3489f
	int ret, pipe1[2];
Packit d3489f
	char buf;
Packit d3489f
Packit d3489f
	if (pipe(pipe1) < 0) {
Packit d3489f
		perror("pipe");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	td.ring = ring;
Packit d3489f
	td.fd = pipe1[0];
Packit d3489f
	td.events = POLLIN;
Packit d3489f
	td.test = __FUNCTION__;
Packit d3489f
Packit d3489f
	pthread_create(&threads[1], NULL, iou_poll, &td);
Packit d3489f
	pthread_create(&threads[0], NULL, poll_pipe, &td);
Packit d3489f
	usleep(100000);
Packit d3489f
Packit d3489f
	buf = 0x89;
Packit d3489f
	ret = write(pipe1[1], &buf, sizeof(buf));
Packit d3489f
	if (ret != sizeof(buf)) {
Packit d3489f
		fprintf(stderr, "write failed: %d\n", ret);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	pthread_join(threads[0], NULL);
Packit d3489f
	pthread_join(threads[1], NULL);
Packit d3489f
Packit d3489f
	if (td.out[0] != td.out[1]) {
Packit d3489f
		fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
Packit d3489f
							td.out[0], td.out[1]);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int do_pipe_pollout_test(struct io_uring *ring)
Packit d3489f
{
Packit d3489f
	struct thread_data td;
Packit d3489f
	pthread_t threads[2];
Packit d3489f
	int ret, pipe1[2];
Packit d3489f
	char buf;
Packit d3489f
Packit d3489f
	if (pipe(pipe1) < 0) {
Packit d3489f
		perror("pipe");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	td.ring = ring;
Packit d3489f
	td.fd = pipe1[1];
Packit d3489f
	td.events = POLLOUT;
Packit d3489f
	td.test = __FUNCTION__;
Packit d3489f
Packit d3489f
	pthread_create(&threads[0], NULL, poll_pipe, &td);
Packit d3489f
	pthread_create(&threads[1], NULL, iou_poll, &td);
Packit d3489f
	usleep(100000);
Packit d3489f
Packit d3489f
	buf = 0x89;
Packit d3489f
	ret = write(pipe1[1], &buf, sizeof(buf));
Packit d3489f
	if (ret != sizeof(buf)) {
Packit d3489f
		fprintf(stderr, "write failed: %d\n", ret);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	pthread_join(threads[0], NULL);
Packit d3489f
	pthread_join(threads[1], NULL);
Packit d3489f
Packit d3489f
	if (td.out[0] != td.out[1]) {
Packit d3489f
		fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
Packit d3489f
							td.out[0], td.out[1]);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int do_fd_test(struct io_uring *ring, const char *fname, int events)
Packit d3489f
{
Packit d3489f
	struct thread_data td;
Packit d3489f
	pthread_t threads[2];
Packit d3489f
	int fd;
Packit d3489f
Packit d3489f
	fd = open(fname, O_RDONLY);
Packit d3489f
	if (fd < 0) {
Packit d3489f
		perror("open");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	td.ring = ring;
Packit d3489f
	td.fd = fd;
Packit d3489f
	td.events = events;
Packit d3489f
	td.test = __FUNCTION__;
Packit d3489f
Packit d3489f
	pthread_create(&threads[0], NULL, poll_pipe, &td);
Packit d3489f
	pthread_create(&threads[1], NULL, iou_poll, &td);
Packit d3489f
Packit d3489f
	pthread_join(threads[0], NULL);
Packit d3489f
	pthread_join(threads[1], NULL);
Packit d3489f
Packit d3489f
	if (td.out[0] != td.out[1]) {
Packit d3489f
		fprintf(stderr, "%s: res %x/%x differ\n", __FUNCTION__,
Packit d3489f
							td.out[0], td.out[1]);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int iou_epoll_ctl(struct io_uring *ring, int epfd, int fd,
Packit d3489f
			 struct epoll_event *ev)
Packit d3489f
{
Packit d3489f
	struct io_uring_sqe *sqe;
Packit d3489f
	struct io_uring_cqe *cqe;
Packit d3489f
	int ret;
Packit d3489f
Packit d3489f
	sqe = io_uring_get_sqe(ring);
Packit d3489f
	if (!sqe) {
Packit d3489f
		fprintf(stderr, "Failed to get sqe\n");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	io_uring_prep_epoll_ctl(sqe, epfd, fd, EPOLL_CTL_ADD, ev);
Packit d3489f
Packit d3489f
	ret = io_uring_submit(ring);
Packit d3489f
	if (ret != 1) {
Packit d3489f
		fprintf(stderr, "submit: %d\n", ret);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = io_uring_wait_cqe(ring, &cqe);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "wait_cqe: %d\n", ret);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = cqe->res;
Packit d3489f
	io_uring_cqe_seen(ring, cqe);
Packit d3489f
	return ret;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int do_test_epoll(struct io_uring *ring, int iou_epoll_add)
Packit d3489f
{
Packit d3489f
	struct epoll_event ev;
Packit d3489f
	struct thread_data td;
Packit d3489f
	pthread_t threads[2];
Packit d3489f
	int ret, pipe1[2];
Packit d3489f
	char buf;
Packit d3489f
	int fd;
Packit d3489f
Packit d3489f
	fd = epoll_create1(0);
Packit d3489f
	if (fd < 0) {
Packit d3489f
		perror("epoll_create");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (pipe(pipe1) < 0) {
Packit d3489f
		perror("pipe");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ev.events = EPOLLIN;
Packit d3489f
	ev.data.fd = pipe1[0];
Packit d3489f
Packit d3489f
	if (!iou_epoll_add) {
Packit d3489f
		if (epoll_ctl(fd, EPOLL_CTL_ADD, pipe1[0], &ev) < 0) {
Packit d3489f
			perror("epoll_ctrl");
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
	} else {
Packit d3489f
		ret = iou_epoll_ctl(ring, fd, pipe1[0], &ev;;
Packit d3489f
		if (ret == -EINVAL) {
Packit d3489f
			fprintf(stdout, "epoll not supported, skipping\n");
Packit d3489f
			return 0;
Packit d3489f
		} else if (ret < 0) {
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	td.ring = ring;
Packit d3489f
	td.fd = fd;
Packit d3489f
	td.events = POLLIN;
Packit d3489f
	td.test = __FUNCTION__;
Packit d3489f
Packit d3489f
	pthread_create(&threads[0], NULL, iou_poll, &td);
Packit d3489f
	pthread_create(&threads[1], NULL, epoll_wait_fn, &td);
Packit d3489f
	usleep(100000);
Packit d3489f
Packit d3489f
	buf = 0x89;
Packit d3489f
	ret = write(pipe1[1], &buf, sizeof(buf));
Packit d3489f
	if (ret != sizeof(buf)) {
Packit d3489f
		fprintf(stderr, "write failed: %d\n", ret);
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	pthread_join(threads[0], NULL);
Packit d3489f
	pthread_join(threads[1], NULL);
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
int main(int argc, char *argv[])
Packit d3489f
{
Packit d3489f
	struct io_uring ring;
Packit d3489f
	const char *fname;
Packit d3489f
	int ret;
Packit d3489f
Packit d3489f
	ret = io_uring_queue_init(1, &ring, 0);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "ring setup failed\n");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = do_pipe_pollin_test(&ring);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "pipe pollin test failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = do_pipe_pollout_test(&ring);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "pipe pollout test failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = do_test_epoll(&ring, 0);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "epoll test 0 failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = do_test_epoll(&ring, 1);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "epoll test 1 failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (argc > 1)
Packit d3489f
		fname = argv[1];
Packit d3489f
	else
Packit d3489f
		fname = argv[0];
Packit d3489f
Packit d3489f
	ret = do_fd_test(&ring, fname, POLLIN);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "fd test IN failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = do_fd_test(&ring, fname, POLLOUT);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "fd test OUT failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = do_fd_test(&ring, fname, POLLOUT | POLLIN);
Packit d3489f
	if (ret) {
Packit d3489f
		fprintf(stderr, "fd test IN|OUT failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return 0;
Packit d3489f
Packit d3489f
}