public inbox for [email protected]
 help / color / mirror / Atom feed
* [PATCH liburing] add tests for nonblocking accept sockets
@ 2022-03-24 14:35 Dylan Yudaken
  2022-03-24 18:12 ` Jens Axboe
  0 siblings, 1 reply; 2+ messages in thread
From: Dylan Yudaken @ 2022-03-24 14:35 UTC (permalink / raw)
  To: Jens Axboe, Pavel Begunkov, io-uring; +Cc: kernel-team, Dylan Yudaken

Add tests for accept sockets with O_NONBLOCK. Add a test for queueing the
accept both before and after connect(), which tests slightly different
code paths. After connect() has always worked, but before required changes
to the kernel.

Signed-off-by: Dylan Yudaken <[email protected]>
---
 test/accept.c | 132 +++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 97 insertions(+), 35 deletions(-)

diff --git a/test/accept.c b/test/accept.c
index af2997f..e2c6b51 100644
--- a/test/accept.c
+++ b/test/accept.c
@@ -59,27 +59,32 @@ static void queue_recv(struct io_uring *ring, int fd, bool fixed)
 		sqe->flags |= IOSQE_FIXED_FILE;
 }
 
-static int accept_conn(struct io_uring *ring, int fd, bool fixed)
+static void queue_accept_conn(struct io_uring *ring, int fd, int fixed_idx)
 {
 	struct io_uring_sqe *sqe;
-	struct io_uring_cqe *cqe;
-	int ret, fixed_idx = 0;
+	int ret;
 
 	sqe = io_uring_get_sqe(ring);
-	if (!fixed)
+	if (fixed_idx < 0)
 		io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
 	else
 		io_uring_prep_accept_direct(sqe, fd, NULL, NULL, 0, fixed_idx);
 
 	ret = io_uring_submit(ring);
 	assert(ret != -1);
+}
+
+static int accept_conn(struct io_uring *ring, int fixed_idx)
+{
+	struct io_uring_cqe *cqe;
+	int ret;
 
 	ret = io_uring_wait_cqe(ring, &cqe);
 	assert(!ret);
 	ret = cqe->res;
 	io_uring_cqe_seen(ring, cqe);
 
-	if (fixed) {
+	if (fixed_idx >= 0) {
 		if (ret > 0) {
 			close(ret);
 			return -EINVAL;
@@ -90,11 +95,13 @@ static int accept_conn(struct io_uring *ring, int fd, bool fixed)
 	return ret;
 }
 
-static int start_accept_listen(struct sockaddr_in *addr, int port_off)
+static int start_accept_listen(struct sockaddr_in *addr, int port_off,
+			       int extra_flags)
 {
 	int fd, ret;
 
-	fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
+	fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | extra_flags,
+		    IPPROTO_TCP);
 
 	int32_t val = 1;
 	ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
@@ -119,14 +126,23 @@ static int start_accept_listen(struct sockaddr_in *addr, int port_off)
 	return fd;
 }
 
-static int test(struct io_uring *ring, int accept_should_error, bool fixed)
+struct accept_test_args {
+	int accept_should_error;
+	bool fixed;
+	bool nonblock;
+	bool queue_accept_before_connect;
+};
+
+static int test(struct io_uring *ring, struct accept_test_args args)
 {
 	struct io_uring_cqe *cqe;
 	struct sockaddr_in addr;
 	uint32_t head, count = 0;
 	int ret, p_fd[2], done = 0;
 
-	int32_t val, recv_s0 = start_accept_listen(&addr, 0);
+	int32_t val;
+	int32_t recv_s0 = start_accept_listen(&addr, 0,
+					      args.nonblock ? O_NONBLOCK : 0);
 
 	p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
 
@@ -141,6 +157,9 @@ static int test(struct io_uring *ring, int accept_should_error, bool fixed)
 	ret = fcntl(p_fd[1], F_SETFL, flags);
 	assert(ret != -1);
 
+	if (args.queue_accept_before_connect)
+		queue_accept_conn(ring, recv_s0, args.fixed ? 0 : -1);
+
 	ret = connect(p_fd[1], (struct sockaddr*)&addr, sizeof(addr));
 	assert(ret == -1);
 
@@ -151,18 +170,21 @@ static int test(struct io_uring *ring, int accept_should_error, bool fixed)
 	ret = fcntl(p_fd[1], F_SETFL, flags);
 	assert(ret != -1);
 
-	p_fd[0] = accept_conn(ring, recv_s0, fixed);
+	if (!args.queue_accept_before_connect)
+		queue_accept_conn(ring, recv_s0, args.fixed ? 0 : -1);
+
+	p_fd[0] = accept_conn(ring, args.fixed ? 0 : -1);
 	if (p_fd[0] == -EINVAL) {
-		if (accept_should_error)
+		if (args.accept_should_error)
 			goto out;
-		if (fixed)
+		if (args.fixed)
 			fprintf(stdout, "Fixed accept not supported, skipping\n");
 		else
 			fprintf(stdout, "Accept not supported, skipping\n");
 		no_accept = 1;
 		goto out;
 	} else if (p_fd[0] < 0) {
-		if (accept_should_error &&
+		if (args.accept_should_error &&
 		    (p_fd[0] == -EBADF || p_fd[0] == -EINVAL))
 			goto out;
 		fprintf(stderr, "Accept got %d\n", p_fd[0]);
@@ -170,7 +192,7 @@ static int test(struct io_uring *ring, int accept_should_error, bool fixed)
 	}
 
 	queue_send(ring, p_fd[1]);
-	queue_recv(ring, p_fd[0], fixed);
+	queue_recv(ring, p_fd[0], args.fixed);
 
 	ret = io_uring_submit_and_wait(ring, 2);
 	assert(ret != -1);
@@ -194,13 +216,13 @@ static int test(struct io_uring *ring, int accept_should_error, bool fixed)
 	}
 
 out:
-	if (!fixed)
+	if (!args.fixed)
 		close(p_fd[0]);
 	close(p_fd[1]);
 	close(recv_s0);
 	return 0;
 err:
-	if (!fixed)
+	if (!args.fixed)
 		close(p_fd[0]);
 	close(p_fd[1]);
 	close(recv_s0);
@@ -222,7 +244,7 @@ static int test_accept_pending_on_exit(void)
 	ret = io_uring_queue_init(32, &m_io_uring, 0);
 	assert(ret >= 0);
 
-	fd = start_accept_listen(NULL, 0);
+	fd = start_accept_listen(NULL, 0, 0);
 
 	sqe = io_uring_get_sqe(&m_io_uring);
 	io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
@@ -242,7 +264,7 @@ static int test_accept_pending_on_exit(void)
 /*
  * Test issue many accepts and see if we handle cancellation on exit
  */
-static int test_accept_many(unsigned nr, unsigned usecs)
+static int test_accept_many(unsigned nr, unsigned usecs, bool nonblock)
 {
 	struct io_uring m_io_uring;
 	struct io_uring_cqe *cqe;
@@ -270,7 +292,8 @@ static int test_accept_many(unsigned nr, unsigned usecs)
 	fds = t_calloc(nr, sizeof(int));
 
 	for (i = 0; i < nr; i++)
-		fds[i] = start_accept_listen(NULL, i);
+		fds[i] = start_accept_listen(NULL, i,
+					     nonblock ? O_NONBLOCK : 0);
 
 	for (i = 0; i < nr; i++) {
 		sqe = io_uring_get_sqe(&m_io_uring);
@@ -286,12 +309,15 @@ static int test_accept_many(unsigned nr, unsigned usecs)
 	for (i = 0; i < nr; i++) {
 		if (io_uring_peek_cqe(&m_io_uring, &cqe))
 			break;
-		if (cqe->res != -ECANCELED) {
-			fprintf(stderr, "Expected cqe to be cancelled\n");
-			goto err;
+		if (cqe->res != -ECANCELED &&
+		    !(cqe->res == -EAGAIN && nonblock)) {
+			fprintf(stderr, "Expected cqe to be cancelled %d\n", cqe->res);
+			ret = 1;
+			goto out;
 		}
 		io_uring_cqe_seen(&m_io_uring, cqe);
 	}
+	ret = 0;
 out:
 	rlim.rlim_cur = cur_lim;
 	if (setrlimit(RLIMIT_NPROC, &rlim) < 0) {
@@ -301,10 +327,7 @@ out:
 
 	free(fds);
 	io_uring_queue_exit(&m_io_uring);
-	return 0;
-err:
-	ret = 1;
-	goto out;
+	return ret;
 }
 
 static int test_accept_cancel(unsigned usecs)
@@ -317,7 +340,7 @@ static int test_accept_cancel(unsigned usecs)
 	ret = io_uring_queue_init(32, &m_io_uring, 0);
 	assert(ret >= 0);
 
-	fd = start_accept_listen(NULL, 0);
+	fd = start_accept_listen(NULL, 0, 0);
 
 	sqe = io_uring_get_sqe(&m_io_uring);
 	io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
@@ -372,10 +395,27 @@ static int test_accept(void)
 {
 	struct io_uring m_io_uring;
 	int ret;
+	struct accept_test_args args = { };
 
 	ret = io_uring_queue_init(32, &m_io_uring, 0);
 	assert(ret >= 0);
-	ret = test(&m_io_uring, 0, false);
+	ret = test(&m_io_uring, args);
+	io_uring_queue_exit(&m_io_uring);
+	return ret;
+}
+
+static int test_accept_nonblock(bool queue_before_connect)
+{
+	struct io_uring m_io_uring;
+	int ret;
+	struct accept_test_args args = {
+		.nonblock = true,
+		.queue_accept_before_connect = queue_before_connect
+	};
+
+	ret = io_uring_queue_init(32, &m_io_uring, 0);
+	assert(ret >= 0);
+	ret = test(&m_io_uring, args);
 	io_uring_queue_exit(&m_io_uring);
 	return ret;
 }
@@ -384,12 +424,15 @@ static int test_accept_fixed(void)
 {
 	struct io_uring m_io_uring;
 	int ret, fd = -1;
+	struct accept_test_args args = {
+		.fixed = true
+	};
 
 	ret = io_uring_queue_init(32, &m_io_uring, 0);
 	assert(ret >= 0);
 	ret = io_uring_register_files(&m_io_uring, &fd, 1);
 	assert(ret == 0);
-	ret = test(&m_io_uring, 0, true);
+	ret = test(&m_io_uring, args);
 	io_uring_queue_exit(&m_io_uring);
 	return ret;
 }
@@ -398,7 +441,8 @@ static int test_accept_sqpoll(void)
 {
 	struct io_uring m_io_uring;
 	struct io_uring_params p = { };
-	int ret, should_fail;
+	int ret;
+	struct accept_test_args args = { };
 
 	p.flags = IORING_SETUP_SQPOLL;
 	ret = t_create_ring_params(32, &m_io_uring, &p);
@@ -407,11 +451,11 @@ static int test_accept_sqpoll(void)
 	else if (ret < 0)
 		return ret;
 
-	should_fail = 1;
+	args.accept_should_error = 1;
 	if (p.features & IORING_FEAT_SQPOLL_NONFIXED)
-		should_fail = 0;
+		args.accept_should_error = 0;
 
-	ret = test(&m_io_uring, should_fail, false);
+	ret = test(&m_io_uring, args);
 	io_uring_queue_exit(&m_io_uring);
 	return ret;
 }
@@ -431,6 +475,18 @@ int main(int argc, char *argv[])
 	if (no_accept)
 		return 0;
 
+	ret = test_accept_nonblock(false);
+	if (ret) {
+		fprintf(stderr, "test_accept_nonblock failed\n");
+		return ret;
+	}
+
+	ret = test_accept_nonblock(true);
+	if (ret) {
+		fprintf(stderr, "test_accept_nonblock(queue_before) failed\n");
+		return ret;
+	}
+
 	ret = test_accept_fixed();
 	if (ret) {
 		fprintf(stderr, "test_accept_fixed failed\n");
@@ -455,18 +511,24 @@ int main(int argc, char *argv[])
 		return ret;
 	}
 
-	ret = test_accept_many(128, 0);
+	ret = test_accept_many(128, 0, false);
 	if (ret) {
 		fprintf(stderr, "test_accept_many failed\n");
 		return ret;
 	}
 
-	ret = test_accept_many(128, 100000);
+	ret = test_accept_many(128, 100000, false);
 	if (ret) {
 		fprintf(stderr, "test_accept_many failed\n");
 		return ret;
 	}
 
+	ret = test_accept_many(128, 0, true);
+	if (ret) {
+		fprintf(stderr, "test_accept_many nonblocking failed\n");
+		return ret;
+	}
+
 	ret = test_accept_pending_on_exit();
 	if (ret) {
 		fprintf(stderr, "test_accept_pending_on_exit failed\n");

base-commit: 68c8759abcbff6262e7aa758beec3c9f5696ee46
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-03-24 18:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-03-24 14:35 [PATCH liburing] add tests for nonblocking accept sockets Dylan Yudaken
2022-03-24 18:12 ` Jens Axboe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox