summaryrefslogtreecommitdiffstats
path: root/contrib/libs/liburing/test/poll-race-mshot.c
diff options
context:
space:
mode:
authorthegeorg <[email protected]>2023-07-26 17:26:21 +0300
committerthegeorg <[email protected]>2023-07-26 17:26:21 +0300
commit3785d5f97965bccf048718d8717904cf50f9f8f9 (patch)
treeb7ce8ae67d7eb7fcf7767c54379f0564c281147f /contrib/libs/liburing/test/poll-race-mshot.c
parent1f6b57071583f89299bb5abd3863d594f23c5be5 (diff)
Update contrib/libs/liburing to 2.4
Diffstat (limited to 'contrib/libs/liburing/test/poll-race-mshot.c')
-rw-r--r--contrib/libs/liburing/test/poll-race-mshot.c277
1 files changed, 277 insertions, 0 deletions
diff --git a/contrib/libs/liburing/test/poll-race-mshot.c b/contrib/libs/liburing/test/poll-race-mshot.c
new file mode 100644
index 00000000000..5b2755fab45
--- /dev/null
+++ b/contrib/libs/liburing/test/poll-race-mshot.c
@@ -0,0 +1,277 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: check that racing wakeups don't re-issue a poll multishot,
+ * this can leak ring provided buffers. also test if ring
+ * provided buffers for regular receive can leak if we hit a
+ * poll race.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define NREQS 64
+#define BUF_SIZE 64
+
+static int no_buf_ring;
+
+struct data {
+ pthread_barrier_t barrier;
+ int fd;
+};
+
+static void *thread(void *data)
+{
+ struct data *d = data;
+ char buf[BUF_SIZE];
+ int ret, i, fd;
+
+ memset(buf, 0x5a, BUF_SIZE);
+ pthread_barrier_wait(&d->barrier);
+ fd = d->fd;
+ for (i = 0; i < NREQS; i++) {
+ ret = write(fd, buf, sizeof(buf));
+ if (ret != BUF_SIZE) {
+ if (ret < 0) {
+ perror("write");
+ printf("bad fd %d\n", fd);
+ } else
+ fprintf(stderr, "wrote short %d\n", ret);
+ }
+ }
+ return NULL;
+}
+
+static int test(struct io_uring *ring, struct data *d)
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int fd[2], ret, i;
+ pthread_t t;
+ void *buf, *ptr;
+ void *ret2;
+
+ if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) < 0) {
+ perror("socketpair");
+ return T_EXIT_FAIL;
+ }
+
+ d->fd = fd[1];
+
+ if (posix_memalign((void **) &buf, 16384, BUF_SIZE * NREQS))
+ return T_EXIT_FAIL;
+
+ br = io_uring_setup_buf_ring(ring, NREQS, 1, 0, &ret);
+ if (!br) {
+ if (ret == -EINVAL) {
+ no_buf_ring = 1;
+ return T_EXIT_SKIP;
+ }
+ fprintf(stderr, "buf ring reg %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ptr = buf;
+ for (i = 0; i < NREQS; i++) {
+ io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1,
+ io_uring_buf_ring_mask(NREQS), i);
+ ptr += BUF_SIZE;
+ }
+ io_uring_buf_ring_advance(br, NREQS);
+
+ pthread_create(&t, NULL, thread, d);
+
+ for (i = 0; i < NREQS; i++) {
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_recv(sqe, fd[0], NULL, 0, 0);
+ sqe->flags |= IOSQE_BUFFER_SELECT;
+ sqe->buf_group = 1;
+ }
+
+ pthread_barrier_wait(&d->barrier);
+
+ ret = io_uring_submit(ring);
+ if (ret != NREQS) {
+ fprintf(stderr, "submit %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ i = 0;
+ do {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ i++;
+ if (cqe->res != BUF_SIZE) {
+ fprintf(stderr, "Bad cqe res %d\n", cqe->res);
+ break;
+ }
+ if (cqe->flags & IORING_CQE_F_BUFFER) {
+ int bid = cqe->flags >> 16;
+
+ if (bid > NREQS) {
+ fprintf(stderr, "Bad BID %d\n", bid);
+ return T_EXIT_FAIL;
+ }
+ } else {
+ fprintf(stderr, "No BID set!\n");
+ printf("ret=%d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ if (i > NREQS) {
+ fprintf(stderr, "Got too many requests?\n");
+ return T_EXIT_FAIL;
+ }
+ } while (i < NREQS);
+
+ pthread_join(t, &ret2);
+ free(buf);
+ io_uring_free_buf_ring(ring, br, NREQS, 1);
+ close(fd[0]);
+ close(fd[1]);
+ return T_EXIT_PASS;
+}
+
+static int test_mshot(struct io_uring *ring, struct data *d)
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int fd[2], ret, i;
+ pthread_t t;
+ void *buf, *ptr;
+ void *ret2;
+
+ if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) < 0) {
+ perror("socketpair");
+ return T_EXIT_FAIL;
+ }
+
+ d->fd = fd[1];
+
+ if (posix_memalign((void *) &buf, 16384, BUF_SIZE * NREQS))
+ return T_EXIT_FAIL;
+
+ br = io_uring_setup_buf_ring(ring, NREQS, 1, 0, &ret);
+ if (!br) {
+ fprintf(stderr, "buf ring reg %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ptr = buf;
+ for (i = 0; i < NREQS; i++) {
+ io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1,
+ io_uring_buf_ring_mask(NREQS), i);
+ ptr += BUF_SIZE;
+ }
+ io_uring_buf_ring_advance(br, NREQS);
+
+ pthread_create(&t, NULL, thread, d);
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_recv_multishot(sqe, fd[0], NULL, 0, 0);
+ sqe->flags |= IOSQE_BUFFER_SELECT;
+ sqe->buf_group = 1;
+
+ pthread_barrier_wait(&d->barrier);
+
+ ret = io_uring_submit(ring);
+ if (ret != 1) {
+ fprintf(stderr, "submit %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ i = 0;
+ do {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ i++;
+ if (!(cqe->flags & IORING_CQE_F_MORE))
+ break;
+ if (cqe->res != BUF_SIZE) {
+ fprintf(stderr, "Bad cqe res %d\n", cqe->res);
+ break;
+ }
+ if (cqe->flags & IORING_CQE_F_BUFFER) {
+ int bid = cqe->flags >> 16;
+
+ if (bid > NREQS) {
+ fprintf(stderr, "Bad BID %d\n", bid);
+ return T_EXIT_FAIL;
+ }
+ } else {
+ fprintf(stderr, "No BID set!\n");
+ printf("ret=%d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ if (i > NREQS) {
+ fprintf(stderr, "Got too many requests?\n");
+ return T_EXIT_FAIL;
+ }
+ } while (1);
+
+ if (i != NREQS + 1) {
+ fprintf(stderr, "Only got %d requests\n", i);
+ return T_EXIT_FAIL;
+ }
+
+ pthread_join(t, &ret2);
+ io_uring_free_buf_ring(ring, br, NREQS, 1);
+ free(buf);
+ close(fd[0]);
+ close(fd[1]);
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ struct data d;
+ int i, ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ pthread_barrier_init(&d.barrier, NULL, 2);
+
+ for (i = 0; i < 1000; i++) {
+ io_uring_queue_init(NREQS, &ring, 0);
+ ret = test(&ring, &d);
+ if (ret != T_EXIT_PASS) {
+ if (no_buf_ring)
+ break;
+ fprintf(stderr, "Test failed loop %d\n", i);
+ return T_EXIT_FAIL;
+ }
+ io_uring_queue_exit(&ring);
+ }
+
+ if (no_buf_ring)
+ return T_EXIT_SKIP;
+
+ for (i = 0; i < 1000; i++) {
+ io_uring_queue_init(NREQS, &ring, 0);
+ ret = test_mshot(&ring, &d);
+ if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "Test mshot failed loop %d\n", i);
+ return T_EXIT_FAIL;
+ }
+ io_uring_queue_exit(&ring);
+ }
+
+ return T_EXIT_PASS;
+}