/* SPDX-License-Identifier: MIT */
/*
 * Description: test many files being polled for and updated
 *
 */
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/poll.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <pthread.h>

#include "liburing.h"

#define	NFILES	5000
#define BATCH	500
#define NLOOPS	1000

#define RING_SIZE	512

struct p {
	int fd[2];
	int triggered;
};

static struct p p[NFILES];
static int no_update;

static int arm_poll(struct io_uring *ring, int off)
{
	struct io_uring_sqe *sqe;

	sqe = io_uring_get_sqe(ring);
	if (!sqe) {
		fprintf(stderr, "failed getting sqe\n");
		return 1;
	}

	io_uring_prep_poll_add(sqe, p[off].fd[0], POLLIN);
	sqe->len = 1;
	sqe->user_data = off;
	return 0;
}

static int reap_polls(struct io_uring *ring)
{
	struct io_uring_cqe *cqe;
	int i, ret, off;
	char c;

	for (i = 0; i < BATCH; i++) {
		struct io_uring_sqe *sqe;

		sqe = io_uring_get_sqe(ring);
		/* update event */
		io_uring_prep_poll_update(sqe, (void *)(unsigned long)i, NULL,
					  POLLIN, 2);
		sqe->user_data = 0x12345678;
	}

	ret = io_uring_submit(ring);
	if (ret != BATCH) {
		fprintf(stderr, "submitted %d, %d\n", ret, BATCH);
		return 1;
	}

	for (i = 0; i < 2 * BATCH; i++) {
		ret = io_uring_wait_cqe(ring, &cqe);
		if (ret) {
			fprintf(stderr, "wait cqe %d\n", ret);
			return ret;
		}
		off = cqe->user_data;
		if (off == 0x12345678)
			goto seen;
		p[off].triggered = 0;
		ret = read(p[off].fd[0], &c, 1);
		if (ret != 1) {
			if (ret == -1 && errno == EAGAIN)
				goto seen;
			fprintf(stderr, "read got %d/%d\n", ret, errno);
			break;
		}
seen:
		io_uring_cqe_seen(ring, cqe);
	}

	if (i != 2 * BATCH) {
		fprintf(stderr, "gave up at %d\n", i);
		return 1;
	}

	return 0;
}

static int trigger_polls(void)
{
	char c = 89;
	int i, ret;

	for (i = 0; i < BATCH; i++) {
		int off;

		do {
			off = rand() % NFILES;
			if (!p[off].triggered)
				break;
		} while (1);

		p[off].triggered = 1;
		ret = write(p[off].fd[1], &c, 1);
		if (ret != 1) {
			fprintf(stderr, "write got %d/%d\n", ret, errno);
			return 1;
		}
	}

	return 0;
}

static void *trigger_polls_fn(void *data)
{
	trigger_polls();
	return NULL;
}

static int check_no_update(struct io_uring *ring)
{
	struct io_uring_cqe *cqe;
	int ret;

	ret = io_uring_wait_cqe(ring, &cqe);
	if (ret)
		return 0;
	ret = cqe->res;
	io_uring_cqe_seen(ring, cqe);
	return ret == -EINVAL;
}

static int arm_polls(struct io_uring *ring)
{
	int ret, to_arm = NFILES, i, off;

	off = 0;
	while (to_arm) {
		int this_arm;

		this_arm = to_arm;
		if (this_arm > RING_SIZE)
			this_arm = RING_SIZE;

		for (i = 0; i < this_arm; i++) {
			if (arm_poll(ring, off)) {
				fprintf(stderr, "arm failed at %d\n", off);
				return 1;
			}
			off++;
		}

		ret = io_uring_submit(ring);
		if (ret != this_arm) {
			if (ret > 0 && check_no_update(ring)) {
				no_update = 1;
				return 0;
			}
			fprintf(stderr, "submitted %d, %d\n", ret, this_arm);
			return 1;
		}
		to_arm -= this_arm;
	}

	return 0;
}

int main(int argc, char *argv[])
{
	struct io_uring ring;
	struct io_uring_params params = { };
	struct rlimit rlim;
	pthread_t thread;
	int i, ret;

	if (argc > 1)
		return 0;

	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
		perror("getrlimit");
		goto err_noring;
	}

	if (rlim.rlim_cur < (2 * NFILES + 5)) {
		rlim.rlim_cur = (2 * NFILES + 5);
		rlim.rlim_max = rlim.rlim_cur;
		if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
			if (errno == EPERM)
				goto err_nofail;
			perror("setrlimit");
			goto err_noring;
		}
	}

	for (i = 0; i < NFILES; i++) {
		if (pipe(p[i].fd) < 0) {
			perror("pipe");
			goto err_noring;
		}
		fcntl(p[i].fd[0], F_SETFL, O_NONBLOCK);
	}

	params.flags = IORING_SETUP_CQSIZE;
	params.cq_entries = 4096;
	ret = io_uring_queue_init_params(RING_SIZE, &ring, &params);
	if (ret) {
		if (ret == -EINVAL) {
			fprintf(stdout, "No CQSIZE, trying without\n");
			ret = io_uring_queue_init(RING_SIZE, &ring, 0);
			if (ret) {
				fprintf(stderr, "ring setup failed: %d\n", ret);
				return 1;
			}
		}
	}

	if (arm_polls(&ring))
		goto err;
	if (no_update) {
		printf("No poll update support, skipping\n");
		goto done;
	}

	for (i = 0; i < NLOOPS; i++) {
		pthread_create(&thread, NULL, trigger_polls_fn, NULL);
		ret = reap_polls(&ring);
		if (ret)
			goto err;
		pthread_join(thread, NULL);
	}

done:
	io_uring_queue_exit(&ring);
	return 0;
err:
	io_uring_queue_exit(&ring);
err_noring:
	fprintf(stderr, "poll-many failed\n");
	return 1;
err_nofail:
	fprintf(stderr, "poll-many: not enough files available (and not root), "
			"skipped\n");
	return 0;
}
